
if (typeof $ === 'undefined') { throw new Error('This application\'s JavaScript requires jQuery'); }

// APP START
// ----------------------------------- 
var version = '20160623001';
var App = angular.module('angle', [
    'ngRoute',
    'ngAnimate',
    'ngStorage',
    'ngCookies',
    'pascalprecht.translate',
    'ui.bootstrap',
    'ui.router',
    'tmh.dynamicLocale',
    'oc.lazyLoad',
    'cfp.loadingBar',
    'ngSanitize',
    'ngResource',
    'ui.utils',
    'ui.grid',
    'ui.grid.pagination',
    'ui.grid.selection',
    'ui.grid.pinning',
    'ui.grid.exporter',
    'ui.grid.edit',
    'ui.grid.autoResize',
    'ui.grid.treeView',
    'ui.grid.resizeColumns',
    'ui.select',
    'ngDialog'
  ]);

App.run(["$rootScope", "$state", "$stateParams",  '$window', '$templateCache', '$http', '$timeout', '$translate', 'Utils',
    function ($rootScope, $state, $stateParams, $window, $templateCache, $http, $timeout, $translate, utils) {
        // Set reference to access them from any scope
        $rootScope.$state = $state;
        $rootScope.$stateParams = $stateParams;
        $rootScope.$storage = $window.localStorage;
        $rootScope.$translate = $translate

        // Uncomment this to disable template cache
        /*$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
            if (typeof(toState) !== 'undefined'){
            $templateCache.remove(toState.templateUrl);
            }
        });*/

        // Scope Globals
        // ----------------------------------- 
        $rootScope.app = {
            name: 'Tanzhi Admin',
            layout: {
                isFixed: true,
                isCollapsed: false,
                isBoxed: false,
                isFloat: false,
                horizontal: false,
                asideHover: false,
                theme: 'app/css/theme-g.css'
            },
            useFullLayout: false,
            hiddenFooter: false,
            viewAnimation: 'ng-fadeIn',
            user: {},
            isSessionValid: false
        };
        
        //直接刷新页面时判定session状态
        $http.get(utils.getBackendPath('/session/isSessionValid'),{withCredentials: true})
        .then(
            function (response) {
                var result = response.data;
                if (utils.isEmpty(result) || result.isValid == 'false'){
                    $rootScope.app.user = {};
                    $rootScope.app.isSessionValid = false;
                    $state.go('page.login');
                }else{
                    $rootScope.app.isSessionValid = true;
                    $rootScope.app.user = {
                        code: result.code,
                        name: localStorage.NG_TRANSLATE_LANG_KEY == 'zh' ? result.cnname : result.enname,
                        zhname: result.cnname,
                        enname: result.enname,
                        faceUrl: utils.isEmpty(result.faceUrl) ? 'app/img/face.jpg' : result.faceUrl
                    };
                }
            }
        );
    }
]);

/**=========================================================
 * Module: config.js
 * App routes and resources configuration
 =========================================================*/

App.config(['$stateProvider', '$locationProvider', '$urlRouterProvider', 'RouteHelpersProvider',
    function ($stateProvider, $locationProvider, $urlRouterProvider, helper) {
        'use strict';

        // Set the following to true to enable the HTML5 Mode
        // You may have to set <base> tag in index and a routing configuration in your server
        $locationProvider.html5Mode(false);

        $urlRouterProvider.otherwise('/app/loading');
        
        // 
        // Application Routes
        // -----------------------------------       
        $stateProvider
        // 
        // Single Page Routes
        // ----------------------------------- 
        .state('page', {
            url: '/page',
            templateUrl: 'app/pages/page.html',
            resolve: helper.resolveFor('modernizr', 'icons'),
            controller: ["$rootScope", function($rootScope) {
                $rootScope.app.layout.isBoxed = false;
            }]
        })
        .state('page.login', {
            url: '/login',
            title: "Login",
            templateUrl: 'app/pages/login.html' 
        })
        .state('page.404', {
            url: '/404',
            title: "Not Found",
            templateUrl: 'app/pages/404.html'
        })

        .state('app', {
            url: '/app',
            abstract: true,
            templateUrl: helper.basepath('app.html'),
            controller: 'AppController',
            resolve: helper.resolveFor('modernizr', 'icons', 'screenfull', 'ui.grid', 'ui.select', 'ngDialog','toaster','whirl')
        })
        .state('app.loading', {
            url: '/loading',
            template: ''
        })
        .state('app.system-menu', {
            url: '/system/menu',
            templateUrl: helper.basepath('system/menu.html'),
            resolve: helper.resolveFor('ztree')
        })
        .state('app.system-user', {
            url: '/system/user',
            templateUrl: helper.basepath('system/user.html')
        })
        .state('app.system-role', {
            url: '/system/role',
            templateUrl: helper.basepath('system/role.html'),
            resolve: helper.resolveFor('ztree', 'ladda')
        })
        .state('app.system-group', {
            url: '/system/group',
            templateUrl: helper.basepath('system/group.html')
        })
        .state('app.system-job', {
            url: '/system/job',
            templateUrl: helper.basepath('system/job.html')
        })
        .state('app.system-task', {
            url: '/system/task',
            templateUrl: helper.basepath('system/task.html')
        })
        .state('app.system-updateLog', {
            url: '/system/updateLog',
            templateUrl: helper.basepath('system/updateLog.html')
        })
        .state('app.system-updateLogView', {
            url: '/system/updateLogView',
            templateUrl: helper.basepath('system/updateLogView.html')
        })
        .state('app.system-cache', {
            url: '/system/cache',
            templateUrl: helper.basepath('system/cache.html')
        })
        .state('app.system-dict', {
            url: '/system/dict',
            templateUrl: helper.basepath('system/dict.html')
        })
        .state('app.system-commonQueryUrl', {
            url: '/system/commonQueryUrl',
            templateUrl: helper.basepath('system/commonQueryUrl.html')
        })
    }
]).config(['$ocLazyLoadProvider', 'APP_REQUIRES', 
    function ($ocLazyLoadProvider, APP_REQUIRES) {
        'use strict';

        // Lazy Load modules configuration
        $ocLazyLoadProvider.config({
        debug: false,
        events: true,
        modules: APP_REQUIRES.modules
        });

    }
]).config(['$controllerProvider', '$compileProvider', '$filterProvider', '$provide',
    function ( $controllerProvider, $compileProvider, $filterProvider, $provide) {
        'use strict';
        // registering components after bootstrap
        App.controller = $controllerProvider.register;
        App.directive  = $compileProvider.directive;
        App.filter     = $filterProvider.register;
        App.factory    = $provide.factory;
        App.service    = $provide.service;
        App.constant   = $provide.constant;
        App.value      = $provide.value;

    }
]).config(['$translateProvider', 'tmhDynamicLocaleProvider',
    function ($translateProvider, tmhDynamicLocaleProvider) {
        var language = localStorage.NG_TRANSLATE_LANG_KEY ? localStorage.NG_TRANSLATE_LANG_KEY : 'zh';
        $translateProvider.useStaticFilesLoader({
            prefix : 'app/i18n/',
            suffix : '.json?version=' + version
        });
        $translateProvider.preferredLanguage(language);
        $translateProvider.useLocalStorage();
        $translateProvider.usePostCompiling(true);
        
        tmhDynamicLocaleProvider.localeLocationPattern('vendor/angular-i18n/angular-locale_{{locale}}.js');
        tmhDynamicLocaleProvider.defaultLocale(language);
    }
]).config(['cfpLoadingBarProvider', 
    function(cfpLoadingBarProvider) {
        cfpLoadingBarProvider.includeBar = true;
        cfpLoadingBarProvider.includeSpinner = false;
        cfpLoadingBarProvider.latencyThreshold = 500;
        cfpLoadingBarProvider.parentSelector = '.wrapper > section';
    }
]).config(['$uibTooltipProvider', 
    function ($tooltipProvider) {
        $tooltipProvider.options({appendToBody: true});
    }
]).config(["$provide", function($provide){
    $provide.decorator('GridOptions',['$delegate', 'i18nService', function($delegate, i18nService){
        var gridOptions;
        gridOptions = angular.copy($delegate);
        gridOptions.initialize = function(options) {
            var initOptions;
            initOptions = $delegate.initialize(options);
            return initOptions;
        };
        
        var language = localStorage.NG_TRANSLATE_LANG_KEY == 'zh' ? 'zh-cn' : localStorage.NG_TRANSLATE_LANG_KEY || 'zh-cn';

        i18nService.setCurrentLang(language);
        return gridOptions;
    }]);
}]);
/**=========================================================
 * Module: constants.js
 * Define constants to inject across the application
 =========================================================*/
App.constant('APP_COLORS', {
    'primary':                '#5d9cec',
    'success':                '#27c24c',
    'info':                   '#23b7e5',
    'warning':                '#ff902b',
    'danger':                 '#f05050',
    'inverse':                '#131e26',
    'green':                  '#37bc9b',
    'pink':                   '#f532e5',
    'purple':                 '#7266ba',
    'dark':                   '#3a3f51',
    'yellow':                 '#fad732',
    'gray-darker':            '#232735',
    'gray-dark':              '#3a3f51',
    'gray':                   '#dde6e9',
    'gray-light':             '#e4eaec',
    'gray-lighter':           '#edf1f2'
}).constant('APP_MEDIAQUERY', {
    'desktopLG':             1200,
    'desktop':                992,
    'tablet':                 768,
    'mobile':                 480
}).constant('APP_REQUIRES', {
    // jQuery based and standalone scripts
    scripts: {
        'modernizr':          ['vendor/modernizr/modernizr.js'],
        'icons':              ['vendor/skycons/skycons.js',
                               'vendor/fontawesome/css/font-awesome.min.css',
                               'vendor/simple-line-icons/css/simple-line-icons.css'],
        'screenfull':         ['vendor/screenfull/dist/screenfull.js'],
        'ztree':              ['vendor/ztree/js/jquery.ztree.all-3.5.min.js',
                               'vendor/ztree/css/zTreeStyle/metro.css'],
        'sparkline':          ['vendor/sparkline/jquery.sparkline.min.js'], 
        'baidu-map':          ['vendor/baidu/map.js'],
        'baidu-map-heatmap':  ['vendor/baidu/Heatmap_min.js'],
        'classyloader':       ['vendor/jquery-classyloader/js/jquery.classyloader.js'],
        'whirl':              ['vendor/whirl/dist/whirl.min.css'],
        'echarts':            {name: 'echarts',
                               files:['vendor/echarts/dist/echarts.js',
                                      'vendor/echarts-custom/echarts-theme-custom.js'],serie:true},//按顺序加载
        'echarts-map':        ['vendor/echarts/map/js/china.js']
    },
    // Angular based script (use the right module name)
    modules: [  
        {name: 'toaster',                   files: ['vendor/angularjs-toaster/toaster.js',
                                                    'vendor/angularjs-toaster/toaster.css']},
        {name: 'ui.grid',                   files: ['vendor/angular-ui-grid/ui-grid.min.css']},  
        {name: 'ui.select',                 files: ['vendor/angular-ui-select/dist/select.css']},
        {name: 'ngDialog',                  files: ['vendor/ng-dialog/css/ngDialog.min.css',
                                                    'vendor/ng-dialog/css/ngDialog-theme-default.min.css']},
        {name: 'ladda',                     files: ['vendor/ladda/dist/ladda-themeless.min.css',
                                                    'vendor/ladda/dist/spin.min.js',
                                                    'vendor/ladda/dist/ladda.min.js',
                                                    'vendor/angular-ladda/dist/angular-ladda.min.js'], serie: true},
    ]
}).constant('BACKEND_PATH','http://192.168.199.188:8981')
;
/**=========================================================
 * Module: login.js
 * login api
 =========================================================*/

App.controller('LoginController', ['$scope', '$rootScope', '$translate', '$state', '$http', 'Utils',
    function($scope, $rootScope, $translate, $state, $http, utils) {
        // bind here all data from the form
        $scope.account = {};
        // place the message if something goes wrong
        $scope.authMsg = '';
        $scope.needCaptha = false;

        $scope.login = function() {
            $scope.authMsg = '';

            if($scope.loginForm.$valid) {
                $http({
                    url: utils.getBackendPath('/login'),
                    method: 'POST',
					withCredentials: true, // 跨域
                    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
                    transformRequest: function(obj) {
                        var str = [];
                        for(var p in obj)
                        str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
                        return str.join("&");
                    },
                    data: {
                        'username': $scope.account.username, 
                        'password': $scope.account.password,
                        'remember-me': $scope.account.remember,
                        'captcha': $scope.account.captcha
                    }
                }).then(function(response){
                    var result = response.data;
                    if (result.success == "true") {
                        $rootScope.app.isSessionValid = true;
                        $rootScope.app.user = {
                            code: result.code,
                            name: localStorage.NG_TRANSLATE_LANG_KEY == 'zh' ? result.cnname : result.enname,
                            zhname: result.cnname,
                            enname: result.enname,
                            faceUrl: utils.isEmpty(result.faceUrl) ? 'app/img/face.jpg' : result.faceUrl
                        }
                        $state.go('app.loading');
                    }else{
                        $http({
                            method:'GET',
                            url: utils.getBackendPath('/sysUtil/needCaptcha'),
                            params:{
                                username: $scope.account.username
                            }
                        }).then(
                            function(response){
                                var result = response.data;
                                if (utils.isEmpty(result) || result.needCaptcha == 'true'){
                                    $scope.needCaptha = true;
                                }
                            }
                        );

                        if(result.msg == "ExpiredCaptcha")
                            $scope.authMsg = $translate.instant("login.EXPIRED_CAPTCHA");
                        else if(result.msg == "IncorrectCaptcha")
                            $scope.authMsg = $translate.instant("login.INCORRECT_CAPTCHA");
                        else 
                            $scope.authMsg = $translate.instant("login.INCORRECT_CREDENTIALS");
                    }
                }).catch(function(x) {
                    $scope.authMsg = 'Server Request Error';
                });
            }
           
        };
    }
]);

/**=========================================================
 * Module: main.js
 * Main Application Controller
 =========================================================*/

App.controller('AppController',
    ['$rootScope', '$scope', '$state', '$translate', '$window', '$localStorage', '$timeout', '$http', '$transitions',
     'tmhDynamicLocale', 'i18nService', 'toggleStateService', 'colors', 'browser', 'cfpLoadingBar', 'HttpUtils', 'Utils', 'toaster', 'ngDialog',
    function($rootScope, $scope, $state, $translate, $window, $localStorage, $timeout, $http, $transitions,
             tmhDynamicLocale,i18nService, toggle, colors, browser, cfpLoadingBar, httpUtils, utils, toaster, ngDialog) {
        "use strict";

        // Setup the layout mode
        $rootScope.app.layout.horizontal = ( $rootScope.$stateParams.layout == 'app-h') ;

        //log event
        $transitions.onSuccess({}, function(transition) {
            httpUtils.post('/sysUtil/logVisitMenu',{state: transition.to().name});
        });

        $transitions.onSuccess({}, function(transition) {
            // display new view from top
            $window.scrollTo(0, 0);
            if (!utils.isEmpty($scope.userMenus[transition.to().name])){
                setCurrentTitle(transition.to().name);
            }
        });

        $transitions.onError({}, function(transition) {
            console.log(transition);
        });
    
        $rootScope.pageTitle = function() {
            var title = $rootScope.app.name;
            document.title = title;
            return title; 
        };
        
        // Allows to use branding color with interpolation
        // {{ colorByName('primary') }}
        $scope.colorByName = colors.byName;
   
//==============================================offsidebar-information====================================================    

 
//==============================================offsidebar-setting====================================================
        // iPad may presents ghost click issues
        // if( ! browser.ipad )
        // FastClick.attach(document.body);

        // Close submenu when sidebar change from collapsed to normal
        $rootScope.$watch('app.layout.isCollapsed', function(newValue, oldValue) {
            if( newValue === false )
                $rootScope.$broadcast('closeSidebarMenu');
        });

        // Restore layout settings
        if( angular.isDefined($localStorage.layout) )
            $scope.app.layout = $localStorage.layout;
        else
            $localStorage.layout = $scope.app.layout;

        $rootScope.$watch("app.layout", function () {
            $localStorage.layout = $scope.app.layout;
        }, true);

        $scope.language = {
            // list of available languages
            available: {
                'en':       'English',
                'zh':       'Chinese'
            },
            selected: 'en',
            // display always the current ui language
            init: function () {
                var proposedLanguage = $translate.proposedLanguage() || $translate.use();
                var preferredLanguage = $translate.preferredLanguage(); // we know we have set a preferred one in app.config
                $scope.language.selected = (proposedLanguage || preferredLanguage);
            },
            set: function (localeId, ev) {
                // Set the new idiom
                $translate.use(localeId);
                // save a reference for the current language
                $scope.language.selected = localeId;
                
                tmhDynamicLocale.set(localeId);
                
                i18nService.setCurrentLang(localeId);
                
                $rootScope.app.user.name = $rootScope.app.user[localeId + 'name'];
            }
        };

        $scope.language.init();

        // Restore application classes state
        toggle.restoreState( $(document.body) );

        // cancel click event easily
        $rootScope.cancel = function($event) {
            $event.stopPropagation();
        };
        
//==============================================sidebar====================================================
        // Hides/show user avatar on sidebar
        $scope.userBlockVisible = true;
        
        $scope.toggleUserBlock = function(){
            $scope.userBlockVisible = !$scope.userBlockVisible;
        };
        
        //menus
        var collapseList = [];

        // demo: when switch from collapse to hover, close all items
        $rootScope.$watch('app.layout.asideHover', function(oldVal, newVal){
            if (newVal === false && oldVal === true) {
                closeAllBut(-1);
            }
        });

        // Check item and children active state
        var isActive = function(item) {
            if (!item) return;

            if (!item.sref || item.sref == '#') {
                var foundActive = false;
                angular.forEach(item.children, function(value, key) {
                    if (isActive(value)) foundActive = true;
                });
                return foundActive;
            }else
                return $state.is(item.sref) || $state.includes(item.sref);
        };

        // Load menu
        $scope.getMenuItemPropClasses = function(item) {
            return (item.is_head == 1 ? 'nav-heading' : '') +
                    (isActive(item) ? ' active' : '') ;
        };

        $scope.loadSidebarMenu = function() {
            var promise = httpUtils.promise('/sysMenu/getUserMenus');
            promise.then(function(result) {
                var datas = result.data.datas;
                $scope.menuItems = datas;
                var firstMenu, hasFirst = false, 
                    stateToGo = $rootScope.stateToGo, isStateToGoValid = false, 
                    userMenus = {},
                    userMenusByID = {};

                var addMenu = function(menu){   
                    userMenusByID["id_" + menu.tid] = menu;
                    if (utils.isEmpty(menu.children)){        
                        userMenus[menu.sref] = menu;
                        
                        if (!utils.isEmpty(stateToGo) && !isStateToGoValid && menu.sref === stateToGo){
                            isStateToGoValid = true;
                        }
                    
                        if (!hasFirst && !utils.isEmpty(menu.sref)){
                            //记录第一个菜单
                            firstMenu = menu.sref;
                            hasFirst = true;
                        }
                    }else {
                        for (var j = 0; j < menu.children.length; j++){
                            addMenu(menu.children[j]);
                        }
                    }
                }
                for (var i = 0; i < datas.length; i++){
                    addMenu(datas[i]);
                }
                
                $scope.userMenus = userMenus;
                $scope.userMenusByID = userMenusByID;
                
                if ($state.current.name == 'app.loading'){
                    if (isStateToGoValid){
                        //从url进入 但由于没登陆 跳转到登录页面
                        $state.go(stateToGo);
                        $rootScope.stateToGo = '-1';
                    }else {
                        //从登录页进入
                        $state.go(firstMenu);
                    }
                }else{
                    //已登录状态 刷新url
                    setCurrentTitle($state.current.name);
                }
            }, function(datas) {  // 错误回调
                console.log('请求失败');
            }); 
        };
        
        var setCurrentTitle = function(stateName){
            var currentMenu = $scope.userMenus[stateName],
                currentTitle = $translate.instant(currentMenu.translate) || currentMenu.label,
                parentMenu = $scope.userMenusByID["id_" + currentMenu.parent_id];
            if(!utils.isEmpty(parentMenu)){
                currentTitle = ($translate.instant(parentMenu.translate) || parentMenu.label) + ' -> ' + currentTitle;
                var grandparentMenu = $scope.userMenusByID["id_" + parentMenu.parent_id];
                if(!utils.isEmpty(grandparentMenu)){
                    currentTitle = ($translate.instant(grandparentMenu.translate) || grandparentMenu.label) + ' -> ' + currentTitle;
                }
            }
            
            $scope.currentTitle = currentTitle;
        }
        
        $scope.loadSidebarMenu();

        // Handle sidebar collapse items
        // ----------------------------------- 

        $scope.addCollapse = function($index, item) {
            collapseList[$index] = $rootScope.app.layout.asideHover ? true : !isActive(item);
        };

        $scope.isCollapse = function($index) {
            return (collapseList[$index]);
        };

        $scope.toggleCollapse = function($index, isParentItem) {
            // collapsed sidebar doesn't toggle drodopwn
            if( utils.isSidebarCollapsed() || $rootScope.app.layout.asideHover ) return true;

            // make sure the item index exists
            if(angular.isDefined(collapseList[$index])) {
                if (!$scope.lastEventFromChild) {
                    collapseList[$index] = !collapseList[$index];
                    closeAllBut($index);
                }
            } else if (isParentItem) {
                closeAllBut(-1);
            }
            
            $scope.lastEventFromChild = isChild($index);

            return true;
        };

        function closeAllBut(index) {
            index += '';
            for(var i in collapseList) {
                if(index < 0 || index.indexOf(i) < 0)
                    collapseList[i] = true;
            }
        }

        function isChild($index) {
            return (typeof $index === 'string') && !($index.indexOf('-') < 0);
        }
        
//==============================================top-navbar====================================================
        $scope.logout = function(){
            httpUtils.post('/logout',{},
                function(result) {
                    $rootScope.app.user = {};
                    $rootScope.app.isSessionValid = false;
                    $scope.userMenus = [];
                    $state.go('page.login');
                }
            );
        }

        $scope.changePassword = function(){
            ngDialog.openConfirm({
                plain: true,
                template: '\
                    <div class="ngdialog-message">\
                        <h5>新密码</h5>\
                        <p><input ng-model="password"/></p>\
                        <div class="ngdialog-buttons">\
                            <button type="button" class="ngdialog-button ngdialog-button-secondary" ng-click="closeThisDialog()">取消</button>\
                            <button type="button" class="ngdialog-button ngdialog-button-primary" ng-click="confirm(password)">确定</button>\
                        </div>\
                    </div>\
                '
            }).then(function (password) {
                httpUtils.post('/sysUser/changePassword',{code: $rootScope.app.user.code, password: password},
                    function(result){
                        if (result.success){
                            toaster.pop('success', '', '修改成功');
                        }else{
                            toaster.pop('error', '', result.msg);
                        }
                    },
                    function(result){
                        toaster.pop('error', '', '修改失败');
                    }
                );
            });
        }
    }
]);

/**=========================================================
 * Controller: SystemCacheController
  =========================================================*/
App.controller('SystemCacheController', ['$scope', 'Utils', 'HttpUtils', 'SimpleUiGrid', 'SimpleSelect',
    function($scope, utils, httpUtils, simpleUiGridService, simpleSelectService) {
        //===========================commonQueryUrlGrid=================================            
        var typeSelect = simpleSelectService.init($scope,
            {
                optionModel: 'type',
                remote: false,
                datas: [
                    {
                        value: 'userRole',
                        name: '用户角色'
                    },
                    {
                        value: 'roleMenu',
                        name: '角色菜单'
                    },
                    {
                        value: 'menuRole',
                        name: '菜单角色'
                    },
                    {
                        value: 'urlMenu',
                        name: '链接菜单'
                    }
                ],
                initValue: 'userRole'
            }
        );
        
        $scope.searchCacheGrid = function() {
            var params = {};
            params.key = $scope.key;
            params.type = typeSelect.getSelected();
 
            httpUtils.get(cacheGrid.options.url,params,
                function (result) {
                    var columns = [];
                    var datas = [];
  
                    if (params.type == "roleMenu"){
                        columns = [
                            {
                                displayName: 'ID',
                                field: 'tid'
                            },
                            {
                                displayName: '菜单',
                                field: 'label'
                            },
                            {
                                displayName: '路由',
                                field: 'sref'
                            }
                        ];
                        if (!utils.isEmpty(result.datas)){
                            datas = result.datas;
                        }
                    } else {
                        columns = [
                            {
                                displayName: '键值',
                                field: 'value'
                            }
                        ];
                        if (!utils.isEmpty(result.datas)){
                            for (var i = 0; i < result.datas.length; i++){
                                datas.push({value: result.datas[i]});
                            }
                        }
                    }
                    
                    $scope['cacheGridOptions'].columnDefs = columns;
                    
                    $scope['cacheGridOptions'].data = datas;
                }
            )
        }; 

        var cacheGrid = simpleUiGridService.init($scope, 
            {
                optionModel: 'cacheGridOptions',
                pageOptionModel: 'cacheGridPageOptions',
                gridApi: 'cacheGridApi',
                url: '/cache/queryCache',
                needPage: false,
                needExport: false
            }
        );

    }
]);

/**=========================================================
 * Controller: SystemCommonQueryUrlController
  =========================================================*/
App.controller('SystemCommonQueryUrlController', ['$scope', 'toaster', 'ngDialog', 'Utils', 'HttpUtils', 'DialogUtils', 'SimpleUiGrid',
    function($scope, toaster, ngDialog, utils, httpUtils, dialogUtils, simpleUiGridService) {
        //===========================commonQueryUrlGrid=================================            
        var commonQueryUrlGridColumns = [
            {
                displayName: 'URL',
                field: 'url'
            },
            {
                displayName: '描述',
                field: 'description'
            },
            { 
                name: '', 
                field: 'widgets', 
                width: '150',
                enableCellEdit: false,
                cellTemplate: '\
                    <div class="ui-grid-cell-contents" style="text-align:center;">\
                        <button ng-click="grid.appScope.saveCommonQueryUrl(row.entity)" title="保存" class="btn btn-xs btn-info">\
                            <em class="fa fa-save"></em>\
                        </button>\
                        <button ng-click="grid.appScope.deleteCommonQueryUrl(row.entity)" title="删除" class="btn btn-xs btn-danger">\
                            <em class="fa fa-trash"></em>\
                        </button>\
                    </div>\
                '
            }
        ];
        
        $scope.searchCommonQueryUrlGrid = function() {
            commonQueryUrlGrid.draw({namespace: 'SystemMapper.getCommonQueryUrls'});
        }; 

        var commonQueryUrlGrid = simpleUiGridService.init($scope, 
            {
                optionModel: 'commonQueryUrlGridOptions',
                pageOptionModel: 'commonQueryUrlGridPageOptions',
                gridApi: 'commonQueryUrlGridApi',
                columns: commonQueryUrlGridColumns,
                pageType: 'common',
                needExport: false,
                menus: [
                    {
                        title: '新增',
                        action: function ($event) {
                            commonQueryUrlGrid.addRow({},0);
                        }
                    }
                ]
            }
        );

        $scope.saveCommonQueryUrl = function(data){
            httpUtils.post('/sysCommonQueryUrl/save',data,
                function(result){
                    if (result.success){
                        if (utils.isEmpty(data.tid)){
                            data.tid = result.msg;
                        }
                        toaster.pop('success', '', '保存成功');
                    }else{
                        toaster.pop('error', '', result.msg);
                    }
                },
                function(){
                    toaster.pop('error', '', '保存失败');
                }
            );
        };
        
        $scope.deleteCommonQueryUrl = function(data){
            dialogUtils.confirm('确定要删除吗?',
                function () {
                    httpUtils.post('/sysCommonQueryUrl/delete',data,
                        function(result){
                            if (result.success){
                                commonQueryUrlGrid.deleteRow(data);
                                toaster.pop('success', '', '删除成功');
                            }else{
                                toaster.pop('error', '', result.msg);
                            }
                        },
                        function(result){
                            toaster.pop('error', '', '删除失败');
                        }
                    );
                }
            );       
        };

        
//===========================init================================= 
        $scope.searchCommonQueryUrlGrid();

    }
]);

/**=========================================================
 * Controller: SystemDictController
  =========================================================*/
App.controller('SystemDictController', ['$scope', 'toaster', 'ngDialog', 'Utils', 'HttpUtils', 'DialogUtils', 'SimpleUiGrid',
    function($scope, toaster, ngDialog, utils, httpUtils, dialogUtils, simpleUiGridService) {
        //===========================dictGrid=================================            
        var dictGridColumns = [
            {
                displayName: '字典代码',
                field: 'code'
            },
            {
                displayName: '字典名称',
                field: 'name'
            },
            {
                displayName: '排序',
                field: 'order_priority'
            },
            {
                displayName: '状态',
                field: 'status'
            },
            {
                displayName: '备注',
                field: 'remark'
            },
            { 
                name: '', 
                field: 'widgets', 
                width: '100',
                enableCellEdit: false,
                cellTemplate: '\
                    <div class="ui-grid-cell-contents" style="text-align:center;">\
                        <button ng-click="grid.appScope.addChildDict(row)" title="增加子字典" class="btn btn-xs btn-warning">\
                            <em class="fa fa-plus"></em>\
                        </button>\
                        <button ng-click="grid.appScope.saveDict(row.entity)" title="保存" class="btn btn-xs btn-info">\
                            <em class="fa fa-save"></em>\
                        </button>\
                        <button ng-click="grid.appScope.deleteDict(row.entity)" title="删除" class="btn btn-xs btn-danger">\
                            <em class="fa fa-trash"></em>\
                        </button>\
                    </div>\
                '
            }
        ];
        
        $scope.queryParams = {namespace: 'SystemMapper.getSysDicts'};
        $scope.searchDictGrid = function() {
            dictGrid.draw($scope.queryParams);
        }; 

        var dictGrid = simpleUiGridService.init($scope, 
            {
                optionModel: 'dictGridOptions',
                pageOptionModel: 'dictGridPageOptions',
                gridApi: 'dictGridApi',
                pageSize: 25,
                pageType: 'common',
                columns: dictGridColumns,
                needExport: false,
                expandable: true,
                controllerSearchFn: $scope.searchDictGrid,
                registerApiFn: function(gridApi){
                    gridApi.treeBase.on.rowExpanded($scope, function(row) {
                        if (!row.entity.$$childrenLoaded){
                            var currentLevel = row.entity.$$treeLevel + 1;
                            httpUtils.get(utils.getQueryListUrl(),
                                {
                                    namespace: 'SystemMapper.getSysDicts',
                                    parentID: row.entity.tid
                                },
                                function(result){
                                    if (!utils.isEmpty(result.datas.gridDatas)){
                                        var index
                                        for (var i = 0; i < $scope.dictGridOptions.data.length; i++){
                                            if (row.entity.$$hashKey === $scope.dictGridOptions.data[i].$$hashKey){
                                                index = i + 1;
                                                break;
                                            }
                                        }
                                        for (var j = 0; j < result.datas.gridDatas.length; j++){
                                            result.datas.gridDatas[j].$$treeLevel = currentLevel;
                                            $scope.dictGridOptions.data.splice(index + j, 0, result.datas.gridDatas[j]);
                                        }
                                        row.entity.$$childrenLoaded = true
                                    }
                                }
                            );
                        }
                    });
                },
                menus: [
                    {
                        title: '新增',
                        action: function ($event) {
                            dictGrid.addRow({status: '1', $$treeLevel: 0, $$childrenLoaded: false},0);
                        }
                    }
                ]
            }
        );
              
        $scope.addChildDict = function(row){
            var index = dictGrid.getIndex(row.entity) + 1;
            var treeLevel = row.entity.$$treeLevel + 1;
            dictGrid.addRow({
                parent_id: row.entity.tid,
                status: '1',
                $$treeLevel: treeLevel,
                $$childrenLoaded: false
            },index);
            dictGrid.expandRow(row);
        }
              
        $scope.saveDict = function(data){
            httpUtils.post('/sysDict/save',data,
                function(result){
                    if (result.success){
                        if (utils.isEmpty(data.tid)){
                            data.tid = result.msg;
                        }
                        toaster.pop('success', '', '保存成功');
                    }else{
                        toaster.pop('error', '', result.msg);
                    }
                },
                function(){
                    toaster.pop('error', '', '保存失败');
                }
            );
        };
        
        $scope.deleteDict = function(data){
            dialogUtils.confirm('确定要删除吗?',
                function () {
                    httpUtils.post('/sysDict/delete',data,
                        function(result){
                            if (result.success){
                                dictGrid.deleteRow(data);
                                toaster.pop('success', '', '删除成功');
                            }else{
                                toaster.pop('error', '', result.msg);
                            }
                        },
                        function(result){
                            toaster.pop('error', '', '删除失败');
                        }
                    );
                }
            );       
        };

        
//===========================init================================= 
        $scope.searchDictGrid();
    }
]);

/**=========================================================
 * Controller: SystemGroupController
  =========================================================*/
App.controller('SystemGroupController', ['$scope', 'toaster', 'ngDialog', 'Utils', 'HttpUtils', 'DialogUtils', 'SimpleUiGrid',
    function($scope, toaster, ngDialog, utils, httpUtils, dialogUtils, simpleUiGridService) {
        $scope.currentGroup = {};
        //===========================groupGrid=================================            
        var groupGridColumns = [
            {
                displayName: '群组名称',
                field: 'name'
            },
            {
                displayName: '群组类型',
                field: 'type'
            },
            {
                displayName: '自定义值',
                field: 'custom_value'
            },
            {
                displayName: '备注',
                field: 'remark'
            },
            {
                displayName: '状态',
                field: 'status',
                width: '80'
            },
            { 
                name: '', 
                field: 'widgets', 
                width: '150',
                enableCellEdit: false,
                cellTemplate: '\
                    <div class="ui-grid-cell-contents" style="text-align:center;">\
                        <button ng-click="grid.appScope.selectUser(row.entity)" title="维护用户" class="btn btn-xs btn-success">\
                            <em class="fa fa-users"></em>\
                        </button>\
                        <button ng-click="grid.appScope.saveGroup(row.entity)" title="保存" class="btn btn-xs btn-info">\
                            <em class="fa fa-save"></em>\
                        </button>\
                        <button ng-click="grid.appScope.deleteGroup(row.entity)" title="删除" class="btn btn-xs btn-danger">\
                            <em class="fa fa-trash"></em>\
                        </button>\
                    </div>\
                '
            }
        ];
        
        $scope.queryParams = {namespace: 'SystemMapper.getAllGroups'};
        $scope.searchGroupGrid = function() {
            $scope.currentGroup = {};
            groupUserGrid.clear();
            groupGrid.draw($scope.queryParams);
        }; 

        var groupGrid = simpleUiGridService.init($scope, 
            {
                optionModel: 'groupGridOptions',
                pageOptionModel: 'groupGridPageOptions',
                gridApi: 'groupGridApi',
                columns: groupGridColumns,
                pageType: 'common',
                needExport: false,
                controllerSearchFn: $scope.searchGroupGrid,
                menus: [
                    {
                        title: '新增',
                        action: function ($event) {
                            groupGrid.addRow({status: '1'},0);
                        }
                    }
                ],
                registerApiFn: function(gridApi){
                    gridApi.selection.on.rowSelectionChanged($scope, function (row, event) {
                        $scope.currentGroup.id = row.entity.tid;
                        searchGroupUserGrid();
                    });
                }
            }
        );
       
        $scope.saveGroup = function(data){
            httpUtils.post('/sysGroup/save',data,
                function(result){
                    if (result.success){
                        if (utils.isEmpty(data.tid)){
                            data.tid = result.msg;
                        }
                        toaster.pop('success', '', '保存成功');
                    }else{
                        toaster.pop('error', '', result.msg);
                    }
                },
                function(){
                    toaster.pop('error', '', '保存失败');
                }
            );
        };
        
        $scope.deleteGroup = function(data){
            dialogUtils.confirm('确定要删除吗?',
                function () {
                    httpUtils.post('/sysGroup/delete',data,
                        function(result){
                            if (result.success){
                                groupGrid.deleteRow(data);
                                groupUserGrid.clear();
                                toaster.pop('success', '', '删除成功');
                            }else{
                                toaster.pop('error', '', result.msg);
                            }
                        },
                        function(result){
                            toaster.pop('error', '', '删除失败');
                        }
                    );
                }
            );
        };
        
        $scope.refreshCache = function(){
             httpUtils.get('/sysGroup/refreshGroupUserCache',{},
                function(result){
                    if (result.success){
                        toaster.pop('success', '', '刷新成功');
                    }else{
                        toaster.pop('error', '', result.msg);
                    }
                },
                function(){
                    toaster.pop('error', '', '刷新失败');
                }
            );
        }
        
        //选择用户
        $scope.selectUser = function(data){
            ngDialog.openConfirm({
                template: 'selectUserDialog',
                className: 'ngdialog-theme-default',
                appendClassName: 'ngdialog-lg',
                scope:$scope,
                controller: ['$scope', function($scope) {
                    $scope.searchOtherUserSelectGrid(data.tid);
                    $scope.searchGroupUserSelectGrid(data.tid);
                }]
            }).then(function (value) {
                var userIDs = '',
                    selectedUsers = groupUserSelectGrid.getAll();
                
                for (var i = 0; i < selectedUsers.length; i++){
                    userIDs += selectedUsers[i].tid + ",";
                }
                
                httpUtils.post('/sysGroup/saveGroupUser',
                    {
                        groupID: $scope.currentGroup.id,
                        userIDs: userIDs
                    },
                    function(result){
                        if (result.success){
                            toaster.pop('success', '', '配置成功');
                            searchGroupUserGrid();
                        }else{
                            toaster.pop('error', '', result.msg);
                        }
                    },
                    function(result){
                        toaster.pop('error', '', '配置失败');
                    }
                );
            });
        }
        
        $scope.goLeft = function(){
            if (otherUserSelectGrid.getSelection().length > 0){
                for (var i = 0; i < otherUserSelectGrid.getSelection().length; i++){
                    groupUserSelectGrid.addRow(otherUserSelectGrid.getSelection()[i]);
                    otherUserSelectGrid.deleteRow(otherUserSelectGrid.getSelection()[i]);
                } 
            }   
        }
        
        $scope.goRight = function(){
            if (groupUserSelectGrid.getSelection().length > 0){
                for (var i = 0; i < groupUserSelectGrid.getSelection().length; i++){
                    otherUserSelectGrid.addRow(groupUserSelectGrid.getSelection()[i]);
                    groupUserSelectGrid.deleteRow(groupUserSelectGrid.getSelection()[i]);
                } 
            }
        }
        
//===========================groupUserGrid=================================        
        var groupUserGridColumns = [
            {
                displayName: '用户编号',
                field: 'code'
            },
            {
                displayName: '用户名称',
                field: 'cnname'
            },
            {
                displayName: '邮箱',
                field: 'email'
            },
            {
                displayName: '状态',
                field: 'status',
                width: '80'
            }
        ];
            
        var searchGroupUserGrid = function() {
            if (utils.isEmpty($scope.currentGroup.id)){
                groupUserGrid.clear();
            }else {
                var params = {
                    namespace: 'SystemMapper.getGroupUser',
                    groupID: $scope.currentGroup.id
                }

                groupUserGrid.draw(params);
            }
        }; 

        var groupUserGrid = simpleUiGridService.init($scope, 
            {
                optionModel: 'groupUserGridOptions',
                gridApi: 'groupUserGridApi',
                needExport: false,
                columns: groupUserGridColumns,
                needPage: false
            }
        );  
 //===========================groupUserSelectGrid=================================
        var groupUserSelectGridColumns = [
            {
                displayName: '用户编号',
                field: 'code'
            },
            {
                displayName: '用户名称',
                field: 'cnname'
            },
            {
                displayName: '状态',
                field: 'status',
                width: '80'
            }
        ];     
               
        $scope.searchGroupUserSelectGrid = function(id) {
            if (utils.isEmpty(id)){
                groupUserSelectGrid.clear();
            }else {
                var params = {
                    namespace: 'SystemMapper.getGroupUser',
                    groupID: id
                }

                groupUserSelectGrid.draw(params);
            }
        }; 

        var groupUserSelectGrid = simpleUiGridService.init($scope, 
            {
                optionModel: 'groupUserSelectGridOptions',
                gridApi: 'groupUserSelectGridApi',
                columns: groupUserSelectGridColumns,
                needPage: false,
                multiSelect: true
            }
        );       
 //===========================otherUserSelectGrid================================= 
        $scope.selectFilterParams = {namespace: 'SystemMapper.getOtherUser'};
        var otherUserSelectGridColumns = [
            {
                displayName: '用户编号',
                field: 'code'
            },
            {
                displayName: '用户名称',
                field: 'cnname'
            }
        ];                 
        $scope.searchOtherUserSelectGrid = function(id) {
            if (utils.isEmpty(id)){
                otherUserSelectGrid.clear();
            }else {
                $scope.selectFilterParams.groupID = id;

                otherUserSelectGrid.draw($scope.selectFilterParams);
            }
        }; 

        var otherUserSelectGrid = simpleUiGridService.init($scope, 
            {
                optionModel: 'otherUserSelectGridOptions',
                gridApi: 'otherUserSelectGridApi',
                columns: otherUserSelectGridColumns,
                needPage: false,
                multiSelect: true
            }
        );  
//===========================init================================= 
        $scope.searchGroupGrid();
    }
]);

/**=========================================================
 * Controller: SystemJobController
  =========================================================*/
App.controller('SystemJobController', ['$scope', 'toaster', 'ngDialog', 'Utils', 'HttpUtils', 'DialogUtils', 'SimpleUiGrid',
    function($scope, toaster, ngDialog, utils, httpUtils, dialogUtils, simpleUiGridService) {
        //===========================jobGrid=================================            
        var jobGridColumns = [
            {
                displayName: '任务组',
                field: 'job_group'
            },
            {
                displayName: '任务名称',
                field: 'job_name'
            },
            {
                displayName: '处理类',
                field: 'class_name'
            },
            {
                displayName: '定时配置',
                field: 'cron',
                width: '150'
            },
            {
                displayName: '备注',
                field: 'remark'
            },
            {
                displayName: '启动状态',
                field: 'jobStatus',
                width: '100'
            },
            {
                displayName: '状态',
                field: 'status',
                width: '80'
            },
            { 
                name: '', 
                field: 'widgets', 
                width: '150',
                enableCellEdit: false,
                cellTemplate: '\
                    <div class="ui-grid-cell-contents" style="text-align:center;">\
                        <button ng-click="grid.appScope.startJob(row.entity)" title="启动任务" class="btn btn-xs btn-success">\
                            <em class="fa fa-caret-square-o-right"></em>\
                        </button>\
                        <button ng-click="grid.appScope.updateCron(row.entity)" title="更新定时配置" class="btn btn-xs btn-warning">\
                            <em class="fa fa-clock-o"></em>\
                        </button>\
                        <button ng-click="grid.appScope.saveJob(row.entity)" title="保存" class="btn btn-xs btn-info">\
                            <em class="fa fa-save"></em>\
                        </button>\
                        <button ng-click="grid.appScope.deleteJob(row.entity)" title="删除" class="btn btn-xs btn-danger">\
                            <em class="fa fa-trash"></em>\
                        </button>\
                    </div>\
                '
            }
        ];
        
        $scope.queryParams = {};
        $scope.searchJobGrid = function() {
            jobGrid.draw($scope.queryParams);
        }; 

        var jobGrid = simpleUiGridService.init($scope, 
            {
                optionModel: 'jobGridOptions',
                pageOptionModel: 'jobGridPageOptions',
                gridApi: 'jobGridApi',
                url: '/sysJob/queryJob',
                pageType: 'common',
                pageSize: 25,
                columns: jobGridColumns,
                needExport: false,
                controllerSearchFn: $scope.searchjobGrid,
                menus: [
                    {
                        title: '新增',
                        action: function ($event) {
                            jobGrid.addRow({status: '1'},0);
                        }
                    }
                ]
            }
        );
        
        $scope.startJob = function(data){
            if (data.status == "0"){
                dialogUtils.alert('无法启动处于停用状态的任务');
            }else if (data.jobStatus == '已启动'){
                dialogUtils.alert('该任务已启动');
            }else{
                httpUtils.post('/sysJob/startJob',data,
                    function(result){
                        if (result.success){
                            data.jobStatus = '已启动';
                            toaster.pop('success', '', '启动成功');
                        }else{
                            toaster.pop('error', '', result.msg);
                        }
                    },
                    function(){
                        toaster.pop('error', '', '启动失败');
                    }
                );
            }
        };
        
        $scope.updateCron = function(data){
            if (data.status == '0'){
                dialogUtils.alert('无法更新处于停用状态的任务');
            }else if (data.jobStatus == '未启动'){
                dialogUtils.alert('该任务尚未启动');
            }else{
                httpUtils.post('/sysJob/updateJobCron',data,
                    function(result){
                        if (result.success){
                            toaster.pop('success', '', '更新成功');
                        }else{
                            toaster.pop('error', '', result.msg);
                        }
                    },
                    function(){
                        toaster.pop('error', '', '更新失败');
                    }
                );
            }
        };
        
        $scope.saveJob = function(data){
            httpUtils.post('/sysJob/save',data,
                function(result){
                    if (result.success){
                        if (utils.isEmpty(data.tid)){
                            data.tid = result.msg;
                        }
                        toaster.pop('success', '', '保存成功');
                    }else{
                        toaster.pop('error', '', result.msg);
                    }
                },
                function(){
                    toaster.pop('error', '', '保存失败');
                }
            );
        };
        
        $scope.deleteJob = function(data){
            dialogUtils.confirm('确定要删除吗?',
                function () {
                    httpUtils.post('/sysJob/delete',data,
                        function(result){
                            if (result.success){
                                jobGrid.deleteRow(data);
                                toaster.pop('success', '', '删除成功');
                            }else{
                                toaster.pop('error', '', result.msg);
                            }
                        },
                        function(result){
                            toaster.pop('error', '', '删除失败');
                        }
                    );
                }
            );       
        };

        
//===========================init================================= 
        $scope.searchJobGrid();
    }
]);

/**=========================================================
 * Controller: SystemMenuController
  =========================================================*/
App.controller('SystemMenuController', ['$scope', 'toaster', 'Utils', 'HttpUtils', 'DialogUtils', 'SimpleUiGrid',
    function($scope, toaster, utils, httpUtils, dialogUtils, simpleUiGridService) {
//===========================tree=================================
        var menuSelectChanged = function(menu){
            $scope.currentMenu = menu;
            searchUrlGrid();
            searchNamespaceGrid();
        }

        httpUtils.get('/sysMenu/getAllMenus',{},function(result){
             $scope.menuTreeOption = {
                name: "menuTree",
                setting: {
                    view: {
                        showLine: true,
                        selectedMulti: false
                    },
                    data: {
                        key: {
                            name: 'label'
                        }
                    },
                    callback: {
                        onClick: function(event, treeId, treeNode) {
                            $scope.$apply(function() {
                                menuSelectChanged(treeNode);
                            });
                        }
                    }
                },
                data: result.datas
             }
        })
        
        $scope.expandAll = function(){
            $scope.menuTree.expandAll(true);
        }
        
        $scope.collapseAll = function(){
            $scope.menuTree.expandAll(false);
        } 

        //新增子菜单
        $scope.addSubMenu = function() {
            if (utils.isEmpty($scope.currentMenu)){
                dialogUtils.alert('请先选中上级菜单');
            }else{
                var newMenu = $scope.menuTree.addNodes($scope.currentMenu, {
                    label: '新菜单',
                    root_id: $scope.currentMenu.root_id,
                    parent_id: $scope.currentMenu.tid,
                    status: '1',
                });
                
                $scope.menuTree.selectNode(newMenu[0]);
                menuSelectChanged(newMenu[0]);
            }
        };
        
        //新增根菜单
        $scope.addRootMenu = function() {
            var newMenu = $scope.menuTree.addNodes(null, {
                label: '新菜单',
                status: '1',
            });
            
            $scope.menuTree.selectNode(newMenu[0]);
            menuSelectChanged(newMenu[0]);
        };
        
        //刷新缓存
        $scope.refreshCache = function(){
             httpUtils.get('/sysMenu/refreshMenuUrlCache?refreshMenuUrlCache=true',{},
                function(result){
                    if (result.success){
                        toaster.pop('success', '', '刷新成功');
                    }else{
                        toaster.pop('error', '', result.msg);
                    }
                },
                function(){
                    toaster.pop('error', '', '刷新失败');
                }
            );
        }
        
        $scope.saveMenu = function(){
            httpUtils.post('/sysMenu/save',$scope.currentMenu,
                function(result){
                    if (result.success){
                        if (utils.isEmpty($scope.currentMenu.tid)){
                            $scope.currentMenu.tid = result.msg;
                        }
                        if (utils.isEmpty($scope.currentMenu.root_id)){
                            $scope.currentMenu.root_id = result.msg;
                        }
                        toaster.pop('success', '', '保存成功');
                    }else{
                        toaster.pop('error', '', result.msg);
                    }
                },
                function(){
                    toaster.pop('error', '', '保存失败');
                }
            );
        }
        
        $scope.deleteMenu = function(){
            if (utils.isEmpty($scope.currentMenu)){
                dialogUtils.alert('请先选中要删除的菜单')
            }else if (utils.isEmpty($scope.currentMenu.children)){ 
                dialogUtils.confirm('确定要删除吗?',
                    function (value) {
                        httpUtils.post('/sysMenu/delete',$scope.currentMenu,
                            function(result){
                                if (result.success){
                                    $scope.menuTree.removeNode($scope.currentMenu);
                                    $scope.currentMenu = null;
                                    urlGrid.clear();
                                    namespaceGrid.clear();
                                    toaster.pop('success', '', '删除成功');
                                }else{
                                    toaster.pop('error', '', result.msg);
                                }
                            },
                            function(result){
                                toaster.pop('error', '', '删除失败');
                            }
                        );
                    }
                );
            }else{    
                dialogUtils.alert('请先删除所有子节点');
            }
        }
//===========================namespaceGrid=================================            
        var namespaceGridColumns = [
            {
                displayName: 'Namespace',
                field: 'namespace'
            },
            {
                displayName: '状态',
                field: 'status',
                width: '80'
            },
            { 
                name: '', 
                field: 'widgets', 
                width: '100',
                enableCellEdit: false,
                cellTemplate: '\
                    <div class="ui-grid-cell-contents" style="text-align:center;">\
                        <button ng-click="grid.appScope.saveMenuNamespace(row.entity)" title="保存" class="btn btn-xs btn-info">\
                            <em class="fa fa-save"></em>\
                        </button>\
                        <button ng-click="grid.appScope.deleteMenuNamespace(row.entity)" title="删除" class="btn btn-xs btn-danger">\
                            <em class="fa fa-trash"></em>\
                        </button>\
                    </div>\
                '
            }
        ];

        var searchNamespaceGrid = function() {
            if (utils.isEmpty($scope.currentMenu.tid)){
                namespaceGrid.clear();
            }else{
                var params = {
                    namespace: 'SystemMapper.getMenuNamespace',
                    menuID: $scope.currentMenu.tid
                }

                namespaceGrid.draw(params);
            }
        }; 

        var namespaceGrid = simpleUiGridService.init($scope, 
            {
                optionModel: 'namespaceGridOptions',
                pageOptionModel: 'namespaceGridPageOptions',
                gridApi: 'namespaceGridApi',
                pageType: 'common',
                needExport: false,
                columns: namespaceGridColumns,
                controllerSearchFn: searchNamespaceGrid,
                menus: [
                    {
                        title: '新增',
                        action: function ($event) {
                            if (!utils.isEmpty($scope.currentMenu)){
                                namespaceGrid.addRow({menu_id: $scope.currentMenu.tid, status: '1'},0);
                            }
                        }
                    }
                ]
            }
        );   
       
        $scope.saveMenuNamespace = function(data){
            httpUtils.post('/sysMenuNamespace/save',data,
                function(result){
                    if (result.success){
                        if (utils.isEmpty(data.tid)){
                            data.tid = result.msg;
                        }
                        toaster.pop('success', '', '保存成功');
                    }else{
                        toaster.pop('error', '', result.msg);
                    }
                },
                function(){
                    toaster.pop('error', '', '保存失败');
                }
            );
        };
        
        $scope.deleteMenuNamespace = function(data){
            dialogUtils.confirm('确定要删除吗?',
                function (value) {
                    httpUtils.post('/sysMenuNamespace/delete',data,
                        function(result){
                            if (result.success){
                                namespaceGrid.deleteRow(data);
                                toaster.pop('success', '', '删除成功');
                            }else{
                                toaster.pop('error', '', result.msg);
                            }
                        },
                        function(result){
                            toaster.pop('error', '', '删除失败');
                        }
                    );
                }
            );
        };

//===========================urlGrid=================================        
        var urlGridColumns = [
            {
                displayName: 'Url',
                field: 'url'
            },
            {
                displayName: '状态',
                field: 'status',
                width: '80'
            },
            { 
                name: '', 
                field: 'widgets', 
                width: '100',
                enableCellEdit: false,
                cellTemplate: '\
                    <div class="ui-grid-cell-contents" style="text-align:center;">\
                        <button ng-click="grid.appScope.saveMenuUrl(row.entity)" title="保存" class="btn btn-xs btn-info">\
                            <em class="fa fa-save"></em>\
                        </button>\
                        <button ng-click="grid.appScope.deleteMenuUrl(row.entity)" title="删除" class="btn btn-xs btn-danger">\
                            <em class="fa fa-trash"></em>\
                        </button>\
                    </div>\
                '
            }
        ];
            
        var searchUrlGrid = function() {
            if (utils.isEmpty($scope.currentMenu.tid)){
                urlGrid.clear();
            }else {
                var params = {
                    namespace: 'SystemMapper.getMenuUrl',
                    menuID: $scope.currentMenu.tid
                }

                urlGrid.draw(params);
            }
        }; 

        var urlGrid = simpleUiGridService.init($scope, 
            {
                optionModel: 'urlGridOptions',
                pageOptionModel: 'urlGridPageOptions',
                gridApi: 'urlGridApi',
                pageType: 'common',
                needExport: false,
                columns: urlGridColumns,
                controllerSearchFn: searchUrlGrid,
                menus: [
                    {
                        title: '新增',
                        action: function ($event) {
                            if (!utils.isEmpty($scope.currentMenu)){
                                urlGrid.addRow({menu_id: $scope.currentMenu.tid, status: '1'},0);
                            }
                        }
                    }
                ]
            }
        );  
        
        $scope.saveMenuUrl = function(data){
            httpUtils.post('/sysMenuUrl/save',data,
                function(result){
                    if (result.success){
                        if (utils.isEmpty(data.tid)){
                            data.tid = result.msg;
                        }
                        toaster.pop('success', '', '保存成功');
                    }else{
                        toaster.pop('error', '', result.msg);
                    }
                },
                function(){
                    toaster.pop('error', '', '保存失败');
                }
            );
        };
        
        $scope.deleteMenuUrl = function(data){
            dialogUtils.confirm('确定要删除吗?',
                function (value) {
                    httpUtils.post('/sysMenuUrl/delete',data,
                        function(result){
                            if (result.success){
                                urlGrid.deleteRow(data);
                                toaster.pop('success', '', '删除成功');
                            }else{
                                toaster.pop('error', '', result.msg);
                            }
                        },
                        function(result){
                            toaster.pop('error', '', '删除失败');
                        }
                    );
                }
            );
        };       
    }
]);

/**=========================================================
 * Controller: SystemRoleController
  =========================================================*/
App.controller('SystemRoleController', ['$scope', 'toaster', 'ngDialog', 'Utils', 'HttpUtils', 'DialogUtils', 'SimpleUiGrid',
    function($scope, toaster, ngDialog, utils, httpUtils, dialogUtils, simpleUiGridService) {
        $scope.currentRole = {};  
//===========================tree=================================
        httpUtils.get('/sysMenu/getAllMenus',{},function(result){
             $scope.menuTreeOption = {
                name: "menuTree",
                setting: {
                    check: {
                        enable: true
                    },
                    view: {
                        showLine: true,
                        selectedMulti: false
                    },
                    data: {
                        key: {
                            name: 'label'
                        }
                    }
                },
                data: result.datas
             }
        })
        
        $scope.expandAll = function(){
            $scope.menuTree.expandAll(true);
        }
        
        $scope.collapseAll = function(){
            $scope.menuTree.expandAll(false);
        } 
        
        var checkTree = function(){
            $scope.menuTree.checkAllNodes(false);
            $scope.menuTree.expandAll(false);
            if (!utils.isEmpty($scope.currentRole.id)){
                var params = {
                    namespace: 'SystemMapper.getRoleMenu',
                    roleID: $scope.currentRole.id
                }
                
                httpUtils.get(utils.getQueryListUrl(),params,
                    function(result){
                        var datas = result.datas.gridDatas;
                        for (var i = 0; i < datas.length; i++){
                            var menuNode = $scope.menuTree.getNodeByParam('tid',datas[i].menu_id);
                            if (!utils.isEmpty(menuNode)){
                                $scope.menuTree.checkNode(menuNode,true);
                                if (menuNode.level == 0){
                                    $scope.menuTree.expandNode(menuNode,true,true,false);
                                }
                            }
                        }
                    }
                );
            }
        }
        
        $scope.saveRoleMenu = function(){
            if (!utils.isEmpty($scope.currentRole.id)){
                $scope.saveButton = 0.1;
                var checkedNodes = $scope.menuTree.getCheckedNodes(),
                    checkedMenus = '';
                for (var i = 0; i < checkedNodes.length; i++){
                    checkedMenus += checkedNodes[i].tid + ','
                }

                $scope.saveButton = 0.8;
                httpUtils.post('/sysRole/saveRoleMenu',
                    {
                        roleID: $scope.currentRole.id,
                        menuIDs: checkedMenus
                    },
                    function(result){
                        if (result.success){
                            toaster.pop('success', '', '保存成功');
                        }else{
                            toaster.pop('error', '', result.msg);
                        }
                        $scope.saveButton = false;
                    },
                    function(){
                        toaster.pop('error', '', '保存失败');
                    }
                );
            }
        }

//===========================roleGrid=================================            
        var roleGridColumns = [
            {
                displayName: '角色编号',
                field: 'code'
            },
            {
                displayName: '角色名称',
                field: 'name'
            },
            {
                displayName: '备注',
                field: 'remark'
            },
            {
                displayName: '状态',
                field: 'status',
                width: '80'
            },
            { 
                name: '', 
                field: 'widgets', 
                width: '100',
                enableCellEdit: false,
                cellTemplate: '\
                    <div class="ui-grid-cell-contents" style="text-align:center;">\
                        <button ng-click="grid.appScope.selectUser(row.entity)" title="维护用户" class="btn btn-xs btn-success">\
                            <em class="fa fa-users"></em>\
                        </button>\
                        <button ng-click="grid.appScope.saveRole(row.entity)" title="保存" class="btn btn-xs btn-info">\
                            <em class="fa fa-save"></em>\
                        </button>\
                        <button ng-click="grid.appScope.deleteRole(row.entity)" title="删除" class="btn btn-xs btn-danger">\
                            <em class="fa fa-trash"></em>\
                        </button>\
                    </div>\
                '
            }
        ];

        $scope.queryParams = {namespace: 'SystemMapper.getAllRoles'};
        $scope.searchRoleGrid = function() {
            $scope.currentRole = {};
            roleUserGrid.clear();
            roleGrid.draw($scope.queryParams);
            if (!utils.isEmpty($scope.menuTree)){
                checkTree();
            }
        }; 

        var roleGrid = simpleUiGridService.init($scope, 
            {
                optionModel: 'roleGridOptions',
                pageOptionModel: 'roleGridPageOptions',
                gridApi: 'roleGridApi',
                pageType: 'common',
                needExport: false,
                columns: roleGridColumns,
                controllerSearchFn: $scope.searchRoleGrid,
                menus: [
                    {
                        title: '新增',
                        action: function ($event) {
                            roleGrid.addRow({status: '1'},0);
                        }
                    }
                ],
                registerApiFn: function(gridApi){
                    gridApi.selection.on.rowSelectionChanged($scope, function (row, event) {
                        $scope.currentRole.id = row.entity.tid;
                        searchRoleUserGrid();
                        checkTree();
                    });
                }
            }
        );   
       
        $scope.saveRole = function(data){
            httpUtils.post('/sysRole/save',data,
                function(result){
                    if (result.success){
                        if (utils.isEmpty(data.tid)){
                            data.tid = result.msg;
                        }
                        $scope.currentRole.id = result.msg;
                        toaster.pop('success', '', '保存成功');
                    }else{
                        toaster.pop('error', '', result.msg);
                    }
                },
                function(){
                    toaster.pop('error', '', '保存失败');
                }
            );
        };
        
        $scope.deleteRole = function(data){
            dialogUtils.confirm('确定要删除吗?',
                function (value) {
                    httpUtils.post('/sysRole/delete',data,
                        function(result){
                            if (result.success){
                                roleGrid.deleteRow(data);
                                toaster.pop('success', '', '删除成功');
                            }else{
                                toaster.pop('error', '', result.msg);
                            }
                        },
                        function(result){
                            toaster.pop('error', '', '删除失败');
                        }
                    );
                }
            );
        };
        
        $scope.refreshCache = function(){
             httpUtils.get('/sysRole/refreshRoleMenuCache?refreshMenuUrlCache=true',{},
                function(result){
                    if (result.success){
                        toaster.pop('success', '', '刷新成功');
                    }else{
                        toaster.pop('error', '', result.msg);
                    }
                },
                function(){
                    toaster.pop('error', '', '刷新失败');
                }
            );
        }
        
        $scope.selectUser = function(data){
            ngDialog.openConfirm({
                template: 'selectUserDialog',
                className: 'ngdialog-theme-default',
                appendClassName: 'ngdialog-lg',
                scope:$scope,
                controller: ['$scope', function($scope) {
                    $scope.searchOtherUserSelectGrid(data.tid);
                    $scope.searchRoleUserSelectGrid(data.tid);
                }]
            }).then(function (value) {
                var userIDs = '',
                    selectedUsers = roleUserSelectGrid.getAll();
                
                for (var i = 0; i < selectedUsers.length; i++){
                    userIDs += selectedUsers[i].tid + ",";
                }
                
                httpUtils.post('/sysRole/saveRoleUser',
                    {
                        roleID: $scope.currentRole.id,
                        userIDs: userIDs
                    },
                    function(result){
                        if (result.success){
                            toaster.pop('success', '', '配置成功');
                            searchRoleUserGrid();
                        }else{
                            toaster.pop('error', '', result.msg);
                        }
                    },
                    function(result){
                        toaster.pop('error', '', '配置失败');
                    }
                );
            });
        }
        
        $scope.goLeft = function(){
            if (otherUserSelectGrid.getSelection().length > 0){
                for (var i = 0; i < otherUserSelectGrid.getSelection().length; i++){
                    roleUserSelectGrid.addRow(otherUserSelectGrid.getSelection()[i]);
                    otherUserSelectGrid.deleteRow(otherUserSelectGrid.getSelection()[i]);
                } 
            }   
        }
        
        $scope.goRight = function(){
            if (roleUserSelectGrid.getSelection().length > 0){
                for (var i = 0; i < roleUserSelectGrid.getSelection().length; i++){
                    otherUserSelectGrid.addRow(roleUserSelectGrid.getSelection()[i]);
                    roleUserSelectGrid.deleteRow(roleUserSelectGrid.getSelection()[i]);
                } 
            }
        }

//===========================roleUserSelectGrid=================================
        var roleUserSelectGridColumns = [
            {
                displayName: '用户编号',
                field: 'code'
            },
            {
                displayName: '用户名称',
                field: 'cnname'
            },
            {
                displayName: '状态',
                field: 'status',
                width: '80'
            }
        ];     
               
        $scope.searchRoleUserSelectGrid = function(id) {
            if (utils.isEmpty(id)){
                roleUserSelectGrid.clear();
            }else {
                var params = {
                    namespace: 'SystemMapper.getRoleUser',
                    roleID: id
                }

                roleUserSelectGrid.draw(params);
            }
        }; 

        var roleUserSelectGrid = simpleUiGridService.init($scope, 
            {
                optionModel: 'roleUserSelectGridOptions',
                gridApi: 'roleUserSelectGridApi',
                columns: roleUserSelectGridColumns,
                needPage: false,
                needExport: false,
                multiSelect: true
            }
        );       
 //===========================otherUserSelectGrid================================= 
        $scope.selectFilterParams = {namespace: 'SystemMapper.getOtherUser'};
        var otherUserSelectGridColumns = [
            {
                displayName: '用户编号',
                field: 'code'
            },
            {
                displayName: '用户名称',
                field: 'cnname'
            }
        ];                 
        $scope.searchOtherUserSelectGrid = function(id) {
            if (utils.isEmpty(id)){
                otherUserSelectGrid.clear();
            }else {
                $scope.selectFilterParams.roleID = id;

                otherUserSelectGrid.draw($scope.selectFilterParams);
            }
        }; 

        var otherUserSelectGrid = simpleUiGridService.init($scope, 
            {
                optionModel: 'otherUserSelectGridOptions',
                gridApi: 'otherUserSelectGridApi',
                columns: otherUserSelectGridColumns,
                needPage: false,
                needExport: false,
                multiSelect: true
            }
        );      
//===========================roleUserGrid=================================        
        var roleUserGridColumns = [
            {
                displayName: '用户编号',
                field: 'code'
            },
            {
                displayName: '用户名称',
                field: 'cnname'
            },
            {
                displayName: '状态',
                field: 'status',
                width: '80'
            }
        ];
            
        var searchRoleUserGrid = function() {
            if (utils.isEmpty($scope.currentRole.id)){
                roleUserGrid.clear();
            }else {
                var params = {
                    namespace: 'SystemMapper.getRoleUser',
                    roleID: $scope.currentRole.id
                }

                roleUserGrid.draw(params);
            }
        }; 

        var roleUserGrid = simpleUiGridService.init($scope, 
            {
                optionModel: 'roleUserGridOptions',
                pageOptionModel: 'roleUserGridPageOptions',
                gridApi: 'roleUserGridApi',
                pageType: 'common',
                needExport: false,
                columns: roleUserGridColumns,
                controllerSearchFn: searchRoleUserGrid
            }
        );   
//===========================init================================= 
        $scope.searchRoleGrid();
    }
]);

/**=========================================================
 * Controller: SystemTaskController
  =========================================================*/
App.controller('SystemTaskController', ['$scope', 'toaster', 'ngDialog', 'Utils', 'HttpUtils', 'DialogUtils', 'SimpleUiGrid',
    function($scope, toaster, ngDialog, utils, httpUtils, dialogUtils, simpleUiGridService) {
        //===========================taskGrid=================================            
        var taskGridColumns = [
            {
                displayName: '任务组',
                field: 'job_group'
            },
            {
                displayName: '任务名称',
                field: 'job_name'
            },
            {
                displayName: '处理类',
                field: 'class_name'
            },
            {
                displayName: '定时配置',
                field: 'cron',
                width: '150'
            },
            {
                displayName: '参数1',
                field: 'param1',
                width: '150'
            },
            {
                displayName: '参数2',
                field: 'param2',
                width: '150'
            },
            {
                displayName: '状态',
                field: 'jobStatus',
                width: '120'
            },
            { 
                name: '', 
                field: 'widgets', 
                width: '150',
                enableCellEdit: false,
                cellTemplate: '\
                    <div class="ui-grid-cell-contents" style="text-align:center;">\
                        <button ng-click="grid.appScope.stopTask(row.entity)" title="暂停任务" class="btn btn-xs btn-success">\
                            <em class="fa fa-pause"></em>\
                        </button>\
                        <button ng-click="grid.appScope.continueTask(row.entity)" title="继续任务" class="btn btn-xs btn-warning">\
                            <em class="fa fa-play"></em>\
                        </button>\
                        <button ng-click="grid.appScope.deleteTask(row.entity)" title="删除任务" class="btn btn-xs btn-info">\
                            <em class="fa fa-close"></em>\
                        </button>\
                        <button ng-click="grid.appScope.runJob(row.entity)" title="立即执行" class="btn btn-xs btn-danger">\
                            <em class="fa fa-arrow-circle-right"></em>\
                        </button>\
                    </div>\
                '
            }
        ];
        
        $scope.queryParams = {};
        $scope.searchTaskGrid = function() {
            taskGrid.draw($scope.queryParams);
        }; 

        var taskGrid = simpleUiGridService.init($scope, 
            {
                optionModel: 'taskGridOptions',
                pageOptionModel: 'taskGridPageOptions',
                gridApi: 'taskGridApi',
                url: '/task/getAllTasks',
                needExport: false,
                needPage: false,
                columns: taskGridColumns
            }
        );
        
        $scope.stopTask = function(data){
            httpUtils.post('/task/stopTask',data,
                function(result){
                    if (result.success){
                        $scope.searchTaskGrid();
                        toaster.pop('success', '', '操作成功');
                    }else{
                        toaster.pop('error', '', result.msg);
                    }
                },
                function(){
                    toaster.pop('error', '', '操作失败');
                }
            );
        };
        
        $scope.continueTask = function(data){
            httpUtils.post('/task/continueTask',data,
                function(result){
                    if (result.success){
                        $scope.searchTaskGrid();
                        toaster.pop('success', '', '操作成功');
                    }else{
                        toaster.pop('error', '', result.msg);
                    }
                },
                function(){
                    toaster.pop('error', '', '操作失败');
                }
            );
        };
        
        $scope.deleteTask = function(data){
            dialogUtils.confirm('确定要删除吗?',
                function () {
                    httpUtils.post('/task/deleteTask',data,
                        function(result){
                            if (result.success){
                                taskGrid.deleteRow(data);
                                toaster.pop('success', '', '删除成功');
                            }else{
                                toaster.pop('error', '', result.msg);
                            }
                        },
                        function(){
                            toaster.pop('error', '', '删除失败');
                        }
                    );
                }
            ); 
        };
        
        $scope.runJob = function(data){
            dialogUtils.confirm('确定要立即执行该任务吗?',
                function () {
                    httpUtils.post('/task/runTask',data,
                        function(result){
                            if (result.success){
                                toaster.pop('success', '', '执行成功');
                            }else{
                                toaster.pop('error', '', result.msg);
                            }
                        },
                        function(result){
                            toaster.pop('error', '', '执行失败');
                        }
                    );
                }
            );       
        };

        
//===========================init================================= 
        $scope.searchTaskGrid();
    }
]);

/**=========================================================
 * Controller: SystemUserController
  =========================================================*/
App.controller('SystemUserController', ['$scope', 'toaster', 'ngDialog', 'Utils', 'HttpUtils', 'DialogUtils', 'SimpleUiGrid',
    function($scope, toaster, ngDialog, utils, httpUtils, dialogUtils, simpleUiGridService) {
        $scope.currentUser = {};
        //===========================userGrid=================================            
        var userGridColumns = [
            {
                displayName: '用户编号',
                field: 'code',
                width: '150'
            },
            {
                displayName: '工号',
                field: 'work_number',
                width: '150'
            },
            {
                displayName: '中文名称',
                field: 'cnname',
                width: '150'
            },
            {
                displayName: '英文名称',
                field: 'enname',
                width: '150'
            },
            {
                displayName: '邮箱',
                field: 'email',
                width: '250'
            },
            {
                displayName: '备注',
                field: 'remark'
            },
            {
                displayName: '状态',
                field: 'status',
                width: '80'
            },
            { 
                name: '', 
                field: 'widgets', 
                width: '150',
                enableCellEdit: false,
                cellTemplate: '\
                    <div class="ui-grid-cell-contents" style="text-align:center;">\
                        <button ng-click="grid.appScope.selectRole(row.entity)" title="维护角色" class="btn btn-xs btn-success">\
                            <em class="fa fa-users"></em>\
                        </button>\
                        <button ng-click="grid.appScope.changePassword(row.entity)" title="修改密码" class="btn btn-xs btn-warning">\
                            <em class="fa fa-key"></em>\
                        </button>\
                        <button ng-click="grid.appScope.saveUser(row.entity)" title="保存" class="btn btn-xs btn-info">\
                            <em class="fa fa-save"></em>\
                        </button>\
                        <button ng-click="grid.appScope.deleteUser(row.entity)" title="删除" class="btn btn-xs btn-danger">\
                            <em class="fa fa-trash"></em>\
                        </button>\
                    </div>\
                '
            }
        ];
        
        $scope.queryParams = {namespace: 'SystemMapper.getAllUsers'};
        $scope.searchUserGrid = function() {
            $scope.currentUser = {};
            userRoleGrid.clear();
            userGrid.draw($scope.queryParams);
        }; 

        var userGrid = simpleUiGridService.init($scope, 
            {
                optionModel: 'userGridOptions',
                pageOptionModel: 'userGridPageOptions',
                gridApi: 'userGridApi',
                columns: userGridColumns,
                pageType: 'common',
                needExport: false,
                remoteSort: true,
                controllerSearchFn: $scope.searchUserGrid,
                menus: [
                    {
                        title: '新增',
                        action: function ($event) {
                            userGrid.addRow({status: '1'},0);
                        }
                    }
                ],
                registerApiFn: function(gridApi){
                    gridApi.selection.on.rowSelectionChanged($scope, function (row, event) {
                        $scope.currentUser.id = row.entity.tid;
                        searchUserRoleGrid();
                    });
                }
            }
        );
       
        $scope.saveUser = function(data){
            httpUtils.post('/sysUser/save',data,
                function(result){
                    if (result.success){
                        if (utils.isEmpty(data.tid)){
                            data.tid = result.msg;
                        }
                        toaster.pop('success', '', '保存成功');
                    }else{
                        toaster.pop('error', '', result.msg);
                    }
                },
                function(){
                    toaster.pop('error', '', '保存失败');
                }
            );
        };
        
        $scope.deleteUser = function(data){
            dialogUtils.confirm('确定要删除吗?',
                function () {
                    httpUtils.post('/sysUser/delete',data,
                        function(result){
                            if (result.success){
                                userGrid.deleteRow(data);
                                userRoleGrid.clear();
                                toaster.pop('success', '', '删除成功');
                            }else{
                                toaster.pop('error', '', result.msg);
                            }
                        },
                        function(result){
                            toaster.pop('error', '', '删除失败');
                        }
                    );
                }
            );
        };
        
        $scope.changePassword = function(data){
            ngDialog.openConfirm({
                plain: true,
                template: '\
                    <div class="ngdialog-message">\
                        <h5>新密码</h5>\
                        <p><input ng-model="password"/></p>\
                        <div class="ngdialog-buttons">\
                            <button type="button" class="ngdialog-button ngdialog-button-secondary" ng-click="closeThisDialog()">取消</button>\
                            <button type="button" class="ngdialog-button ngdialog-button-primary" ng-click="confirm(password)">确定</button>\
                        </div>\
                    </div>\
                '
            }).then(function (password) {
                data.password = password;
                httpUtils.post('/sysUser/changePassword',data,
                    function(result){
                        if (result.success){
                            toaster.pop('success', '', '修改成功');
                        }else{
                            toaster.pop('error', '', result.msg);
                        }
                    },
                    function(result){
                        toaster.pop('error', '', '修改失败');
                    }
                );
            });
        }
        
        $scope.refreshCache = function(){
             httpUtils.get('/sysUser/refreshUserRoleCache',{},
                function(result){
                    if (result.success){
                        toaster.pop('success', '', '刷新成功');
                    }else{
                        toaster.pop('error', '', result.msg);
                    }
                },
                function(){
                    toaster.pop('error', '', '刷新失败');
                }
            );
        }
        
        //选择角色
        $scope.selectRole = function(data){
            ngDialog.openConfirm({
                template: 'selectRoleDialog',
                className: 'ngdialog-theme-default',
                appendClassName: 'ngdialog-lg',
                scope: $scope,
                controller: ['$scope', function($scope) {
                    $scope.searchOtherRoleSelectGrid(data.tid);
                    $scope.searchUserRoleSelectGrid(data.tid);
                }]
            }).then(function (value) {
                var roleIDs = '',
                    selectedRoles = userRoleSelectGrid.getAll();
                
                for (var i = 0; i < selectedRoles.length; i++){
                    roleIDs += selectedRoles[i].tid + ",";
                }
                
                httpUtils.post('/sysUser/saveUserRole',
                    {
                        userID: $scope.currentUser.id,
                        roleIDs: roleIDs
                    },
                    function(result){
                        if (result.success){
                            toaster.pop('success', '', '配置成功');
                            searchUserRoleGrid();
                        }else{
                            toaster.pop('error', '', result.msg);
                        }
                    },
                    function(result){
                        toaster.pop('error', '', '配置失败');
                    }
                );
            });
        }
        
        $scope.goLeft = function(){
            if (otherRoleSelectGrid.getSelection().length > 0){
                for (var i = 0; i < otherRoleSelectGrid.getSelection().length; i++){
                    userRoleSelectGrid.addRow(otherRoleSelectGrid.getSelection()[i]);
                    otherRoleSelectGrid.deleteRow(otherRoleSelectGrid.getSelection()[i]);
                } 
            }   
        }
        
        $scope.goRight = function(){
            if (userRoleSelectGrid.getSelection().length > 0){
                for (var i = 0; i < userRoleSelectGrid.getSelection().length; i++){
                    otherRoleSelectGrid.addRow(userRoleSelectGrid.getSelection()[i]);
                    userRoleSelectGrid.deleteRow(userRoleSelectGrid.getSelection()[i]);
                } 
            }
        }
        
//===========================userRoleGrid=================================        
        var userRoleGridColumns = [
            {
                displayName: '角色编号',
                field: 'code'
            },
            {
                displayName: '角色名称',
                field: 'name'
            },
            {
                displayName: '状态',
                field: 'status',
                width: '80'
            }
        ];
            
        var searchUserRoleGrid = function() {
            if (utils.isEmpty($scope.currentUser.id)){
                userRoleGrid.clear();
            }else {
                var params = {
                    namespace: 'SystemMapper.getUserRole',
                    userID: $scope.currentUser.id
                }

                userRoleGrid.draw(params);
            }
        }; 

        var userRoleGrid = simpleUiGridService.init($scope, 
            {
                optionModel: 'userRoleGridOptions',
                gridApi: 'userRoleGridApi',
                needExport: false,
                columns: userRoleGridColumns,
                needPage: false
            }
        );  
 //===========================userRoleSelectGrid=================================                   
        $scope.searchUserRoleSelectGrid = function(id) {
            if (utils.isEmpty(id)){
                userRoleSelectGrid.clear();
            }else {
                var params = {
                    namespace: 'SystemMapper.getUserRole',
                    userID: id
                }

                userRoleSelectGrid.draw(params);
            }
        }; 

        var userRoleSelectGrid = simpleUiGridService.init($scope, 
            {
                optionModel: 'userRoleSelectGridOptions',
                gridApi: 'userRoleSelectGridApi',
                needExport: false,
                columns: userRoleGridColumns,
                needPage: false,
                multiSelect: true
            }
        );       
 //===========================otherRoleSelectGrid================================= 
        var otherRoleSelectGridColumns = [
            {
                displayName: '角色编号',
                field: 'code'
            },
            {
                displayName: '角色名称',
                field: 'name'
            }
        ];                 
        $scope.searchOtherRoleSelectGrid = function(id) {
            if (utils.isEmpty(id)){
                otherRoleSelectGrid.clear();
            }else {
                var params = {
                    namespace: 'SystemMapper.getOtherRole',
                    userID: id
                }

                otherRoleSelectGrid.draw(params);
            }
        }; 

        var otherRoleSelectGrid = simpleUiGridService.init($scope, 
            {
                optionModel: 'otherRoleSelectGridOptions',
                gridApi: 'otherRoleSelectGridApi',
                needExport: false,
                columns: otherRoleSelectGridColumns,
                needPage: false,
                multiSelect: true
            }
        );  
//===========================init================================= 
        $scope.searchUserGrid();
    }
]);

/**=========================================================
 * Directive: baidu-map.js
 =========================================================*/

App.directive('baiduMap', ["$timeout", 'Utils',
    function($timeout, utils) {
        'use strict';
        
        return {
            restrict: 'EA',
            link: function($scope, $element, $attrs){
                var map = new BMap.Map($attrs.id);
                $scope[utils.isEmpty($attrs.name) ? 'baiduMap' : $attrs.name] = map;
            }
        };
    }
]);

/**=========================================================
 * Directive: captcha.js
 =========================================================*/

App.directive('captcha', ['Utils',
    function(utils) {
        'use strict';
        
        return {
            restrict: 'EA',
            replace: true,
            template: function($element,$attrs){
                return '<img ng-src="{{captchaSrc}}" ng-click="updateCaptcha()" alt="captcha"/>'
            },
            link: function($scope, $element, $attrs){
                $scope.captchaSrc = utils.getBackendPath('/captcha/image');
                $scope.updateCaptcha = function(){
                    $attrs.$set('src', utils.getBackendPath('/captcha/image'));
                }
            }
        };
    }
]);

/**=========================================================
 * Module: classy-loader.js
 * Enable use of classyloader directly from data attributes
 =========================================================*/

App.directive('classyloader', ["$timeout", "Utils", function($timeout, utils) {
    'use strict';

    var $scroller = $(window),
        inViewFlagClass = 'js-is-in-view'; // a classname to detect when a chart has been triggered after scroll

    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            // run after interpolation  
            $timeout(function(){
                var $element = $(element),
                    options  = $element.data();
            
                // At lease we need a data-percentage attribute
                if(options) {
                    if(options.triggerInView ) {

                        $scroller.scroll(function() {
                            checkLoaderInVIew($element, options);
                        });
                        // if the element starts already in view
                        checkLoaderInVIew($element, options);
                    }else{
                        startLoader($element, options);
                    }
                }

                if (!utils.isEmpty(attrs.name)){
                    var level = utils.isEmpty(attrs.level) ? 0 : parseInt(attrs.level),
                        pageScope = scope;
                    for (var i = 0; i < level; i++){
                        pageScope = pageScope.$parent
                    }
                    pageScope[attrs.name] = $element;
                } 
            }, 0);

            function checkLoaderInVIew(element, options) {
                var offset = -20;
                if(!element.hasClass(inViewFlagClass) && Utils.isInView(element, {topoffset: offset}) ) {
                    startLoader(element, options);
                }
            }
            function startLoader(element, options) {
                element.ClassyLoader(options).addClass(inViewFlagClass);
            }
    }
  };
}]);

/**=========================================================
 * Directive: datepicker-range.js
 =========================================================*/

App.directive('rangeDatepicker', ['Utils',
    function(utils) {
        'use strict';
        
        return {
            restrict: 'EA',
            replace: true,
            template: function($element,$attrs){
                var optionModel = utils.isEmpty($attrs.optionModel) ? 'dateRange' : $attrs.optionModel;
                var ngModel = 'rangeDatePickers.' + optionModel;

                return '\
                    <table>\
                        <tr>\
                            <td style="padding:0 8px"><datepicker ng-model="' + ngModel + '.startDate"></datepicker></td>\
                            <td style="padding:0 8px"><span class="control-label">~</span></td>\
                            <td style="padding:0 8px"><datepicker ng-model="' + ngModel + '.endDate"></datepicker></td>\
                        </tr>\
                    </table>\
                '
            },
            link: function($scope, $element, $attrs){
                var optionModel = utils.isEmpty($attrs.optionModel) ? 'dateRange' : $attrs.optionModel;
                var ngModel = 'rangeDatePickers.' + optionModel;
                
                $scope.$watch(ngModel + ".startDate.date", 
                    function (newVal, oldVal) {                       
                        $scope.rangeDatePickers[optionModel].endDate.dateOptions.minDate = newVal;
                    }
                );
                
                $scope.$watch(ngModel + ".endDate.date", 
                    function (newVal, oldVal) {                       
                        $scope.rangeDatePickers[optionModel].startDate.dateOptions.maxDate = newVal;
                    }
                );
            }
        }
    }
]);

/**=========================================================
 * Directive: datepicker-simple.js
 =========================================================*/

App.directive('datepicker', ['Utils',
    function(utils) {
        'use strict';
        
        return {
            restrict: 'EA',
            replace: true,
            template: function($element,$attrs){
                var optionModel = utils.isEmpty($attrs.optionModel) ? 'date' : $attrs.optionModel,
                    ngModel = utils.isEmpty($attrs.ngModel) ? 'datepickers.' + optionModel : $attrs.ngModel,
                    format = utils.isEmpty($attrs.format) ? 'yyyy-MM-dd' : $attrs.format,
                    style = utils.isEmpty($attrs.style) ? "width: 170px;": $attrs.style;
                    
                return '\
                    <p class="input-group" style="' + style + '">\
                        <input type="text" class="form-control" uib-datepicker-popup="' + format + '" ng-model="' + ngModel + '.date" \
                            is-open="' + ngModel + '.opened" datepicker-options="' + ngModel + '.dateOptions" ng-required="true" show-button-bar="false" />\
                        <span class="input-group-btn">\
                            <button type="button" style="height:35px" class="btn btn-default" ng-click="' + ngModel + '.opened=true">\
                                <i class="fa fa-calendar"></i>\
                            </button>\
                        </span>\
                    </p>\
                '
            }
        }
    }
]);

/**=========================================================
 * Directive: double-select.js
 =========================================================*/

App.directive('doubleSelect', ['Utils',
    function(utils) {
        'use strict';
        
        return {
            restrict: 'EA',
            replace: true,
            template: function($element,$attrs){
                var optionModel = $attrs.optionModel,
                    ngModel = utils.isEmpty($attrs.ngModel) ? 'doubleSelects.' + optionModel : $attrs.ngModel,
                    label1 = utils.isEmpty($attrs.label1) ? '' : $attrs.label1,
                    label2 = utils.isEmpty($attrs.label2) ? '' : $attrs.label2;
                return '\
                    <div>\
                        <label class="col-lg-1 control-label">' + label1 + '</label>\
                        <div class="col-lg-5">\
                            <simple-select multiple ng-model="' + ngModel + '.selected1" option-model="' + optionModel + '"></simple-select>\
                        </div>\
                        <label class="col-lg-1 control-label">' + label2 + '</label>\
                        <div class="col-lg-5">\
                            <simple-select multiple ng-model="' + ngModel + '.selected2" option-model="' + optionModel + '"></simple-select>\
                        </div>\
                    </div>\
                '
            }
        }
    }
]);

/**=========================================================
 * Directive: draggableCaptcha.js
 =========================================================*/

App.directive('draggableCaptcha', ['$timeout', 'Utils',
    function($timeout,utils) {
        'use strict';
        
        return {
            restrict: 'EA',
            replace: true,
            template: function($element,$attrs){
                return '\
                    <div class="captcha-wrap">\
                        <div class="captcha-tip">\
                            {{$translate.instant("login.CAPTCHA_TIPS")}}\
                        </div>\
                        <ul class="captcha">\
                            <li class="captchaItem">1</li>\
                            <li class="captchaItem">2</li>\
                            <li class="captchaItem">3</li>\
                            <li class="captchaItem">4</li>\
                            <li class="captchaItem">5</li>\
                            <li class="captchaItem">6</li>\
                        </ul>\
                    </div>\
                '
            },
            link: function($scope, $element, $attrs){
                $timeout(function(){
                    var captcha = $(".captcha");
                    captcha.sortable();
                    captcha.disableSelection();
                    
                    var captchaItems = captcha.children();
                    for(var i = 0; i < captchaItems.length; i++){
                        var j = parseInt(Math.random() * captchaItems.length),
                            x = captchaItems[i];
                        captchaItems[i] = captchaItems[j], 
                        captchaItems[j] = x;
                    }
                    
                    captcha.html(captchaItems);
                },10000)
                
            }
        };
    }
]);

/**=========================================================
 * Directive: echarts.js
 * Initializes the echarts plugin and handles data refresh
 =========================================================*/

App.directive('echarts', ["$timeout", 'Utils',
    function($timeout, utils) {
        'use strict';
        
        return {
            restrict: 'EA',
            scope: {
                option: '='
            },
            link: function($scope, $element, $attrs){
                //解决ngDialog中无法显示的问题
                $timeout(function(){    
                    var myChart = echarts.init($element[0],'echartsTheme');

                    //自适应
                    window.addEventListener("resize", function () {
                        myChart.resize();
                    });
                    
                    var name = utils.isEmpty($attrs.name) ? 'chart' : $attrs.name,
                        level = utils.isEmpty($attrs.level) ? 1 : parseInt($attrs.level),
                        scope = $scope;
                    
                    //找到页面的scope
                    for (var i = 0; i < level; i++){
                        scope = scope['$parent'];
                    }
                    
                    //初始化
                    if (!utils.isEmpty($attrs.option)){
                        var optionPath = $attrs.option.split(".");
                        var option = scope;
                        for (var i = 0; i < optionPath.length; i++){
                            option = option[optionPath[i]];
                            if (utils.isEmpty(option)) break;
                        }
                        if (!utils.isEmpty(option)){
                            myChart.setOption(option,true);
                        }
                    }
                    
                    scope[utils.isEmpty($attrs.name) ? 'chart' : $attrs.name] = myChart;
                    
                    //监听option变化
                    $scope.$watch("option", 
                        function (newVal, oldVal) {
                            if (!utils.isEmpty(newVal) && newVal != oldVal){
                                myChart.setOption(newVal,true);
                                myChart.hideLoading();
                            }
                        }
                    );
                })
            }
        };
    }
]);

/**=========================================================
 * Directive: fullscreen.js
 * Toggle the fullscreen mode on/off
 =========================================================*/

App.directive('toggleFullscreen', function() {
    'use strict';

    return {
        restrict: 'A',
        link: function(scope, element, attrs) {

            element.on('click', function (e) {
                e.preventDefault();

                if (screenfull.enabled) {
                    
                    screenfull.toggle();
                    
                    // Switch icon indicator
                    if(screenfull.isFullscreen)
                        $(this).children('em').removeClass('fa-expand').addClass('fa-compress');
                    else
                        $(this).children('em').removeClass('fa-compress').addClass('fa-expand');

                } else {
                    $.error('Fullscreen not enabled');
                }

            });
        }
    };

});


/**=========================================================
 * Directive: grid-pagination.js
 =========================================================*/

App.directive('gridPagination', [
    function() {
        'use strict';
        
        return {
            restrict: 'EA',
            replace: true,
            template: function($element,$attrs){
                var pinning = $attrs.pinning == undefined ? '' : ' ui-grid-pinning ',
                    tree = $attrs.tree == undefined ? '' : ' ui-grid-tree-view ',
                    edit = $attrs.edit == undefined ? '' : ' ui-grid-edit ';
                return '\
                    <div>\
                        <div ui-grid="' + $attrs.optionModel + '" ui-grid-resize-columns ui-grid-pagination ui-grid-auto-resize ui-grid-selection ' + pinning + tree + edit + 'class="grid table-uigrid" style="' + $attrs.style + '"></div>\
                    </div>\
                '
            },
            link: function($scope, $element, $attrs){
                $scope.$watch($attrs.optionModel + ".status", 
                    function (newVal, oldVal) {   
                        if (newVal == 'loading'){
                            $element.addClass('whirl standard');
                        }else{
                            $element.removeClass('whirl standard');
                        }
                    }
                );
            }
        }
    }
]);

/**=========================================================
 * Directive: navbar-search.js
 * Navbar search toggler * Auto dismiss on ESC key
 =========================================================*/

App.directive('searchOpen', ['navSearch', function(navSearch) {
  'use strict';

  return {
    restrict: 'A',
    controller: ["$scope", "$element", function($scope, $element) {
      $element
        .on('click', function (e) { e.stopPropagation(); })
        .on('click', navSearch.toggle);
    }]
  };

}]).directive('searchDismiss', ['navSearch', function(navSearch) {
  'use strict';

  var inputSelector = '.navbar-form input[type="text"]';

  return {
    restrict: 'A',
    controller: ["$scope", "$element", function($scope, $element) {

      $(inputSelector)
        .on('click', function (e) { e.stopPropagation(); })
        .on('keyup', function(e) {
          if (e.keyCode == 27) // ESC
            navSearch.dismiss();
        });
        
      // click anywhere closes the search
      $(document).on('click', navSearch.dismiss);
      // dismissable options
      $element
        .on('click', function (e) { e.stopPropagation(); })
        .on('click', navSearch.dismiss);
    }]
  };

}]);


/**=========================================================
 * Module panel-tools.js
 * Directive tools to control panels. 
 * Allows collapse, refresh and dismiss (remove)
 * Saves panel state in browser storage
 =========================================================*/

App.directive('paneltool', ["$compile", "$timeout", function($compile, $timeout){
    var templates = {
        /* jshint multistr: true */
        collapse:"<a panel-collapse='' ng-click='{{panelId}} = !{{panelId}}'> \
                    <em ng-show='{{panelId}}' class='fa fa-plus'></em> \
                    <em ng-show='!{{panelId}}' class='fa fa-minus'></em> \
                  </a>",
        dismiss: "<a panel-dismiss=''>\
                    <em class='fa fa-times'></em>\
                  </a>",
        refresh: "<a style='cursor:pointer' panel-refresh='' data-spinner='{{spinner}}'>\
                    <em class='fa fa-refresh'></em>\
                  </a>"
    };

    function getTemplate( elem, attrs ){
        var temp = '';
        attrs = attrs || {};
        if(attrs.toolCollapse)
            temp += templates.collapse.replace(/{{panelId}}/g, (elem.parent().parent().attr('id')) );
        if(attrs.toolDismiss)
            temp += templates.dismiss;
        if(attrs.toolRefresh)
            temp += templates.refresh.replace(/{{spinner}}/g, attrs.toolRefresh);
        return temp;
    }
  
    return {
        restrict: 'E',
        scope: false,
        link: function (scope, element, attrs) {
            var tools = scope.panelTools || attrs;
    
            $timeout(function() {
                element.html(getTemplate(element, tools)).show();
                $compile(element.contents())(scope);
                element.addClass('pull-right');
            });
        }
    };
}])
/**=========================================================
 * Dismiss panels * [panel-dismiss]
 =========================================================*/
.directive('panelDismiss', ["$q", "Utils", function($q, Utils){
    'use strict';
    return {
        restrict: 'A',
        controller: ["$scope", "$element", 
            function ($scope, $element) {
                var removeEvent   = 'panel-remove',
                    removedEvent  = 'panel-removed';

                $element.on('click', function () {

                    // find the first parent panel
                    var parent = $(this).closest('.panel');

                    removeElement();

                    function removeElement() {
                        var deferred = $q.defer();
                        var promise = deferred.promise;
                        
                        // Communicate event destroying panel
                        $scope.$emit(removeEvent, parent.attr('id'), deferred);
                        promise.then(destroyMiddleware);
                    }

                    // Run the animation before destroy the panel
                    function destroyMiddleware() {
                        if(Utils.support.animation) {
                          parent.animo({animation: 'bounceOut'}, destroyPanel);
                        }
                        else destroyPanel();
                    }

                    function destroyPanel() {
                        var col = parent.parent();
                        parent.remove();
                        // remove the parent if it is a row and is empty and not a sortable (portlet)
                        col
                          .filter(function() {
                          var el = $(this);
                          return (el.is('[class*="col-"]:not(.sortable)') && el.children('*').length === 0);
                        }).remove();

                        // Communicate event destroyed panel
                        $scope.$emit(removedEvent, parent.attr('id'));
                    }
                });
            }
        ]
    };
}])
/**=========================================================
 * Collapse panels * [panel-collapse]
 =========================================================*/
.directive('panelCollapse', ['$timeout', function($timeout){
    'use strict';
  
    var storageKeyName = 'panelState',
        storage;
  
    return {
        restrict: 'A',
        scope: false,
        controller: ["$scope", "$element", 
            function ($scope, $element) {
                // Prepare the panel to be collapsible
                var $elem   = $($element),
                    parent  = $elem.closest('.panel'), // find the first parent panel
                    panelId = parent.attr('id');

                storage = $scope.$storage;

                // Load the saved state if exists
                var currentState = loadPanelState( panelId );
                if (typeof currentState !== 'undefined') {
                  $timeout(function(){
                      $scope[panelId] = currentState; },
                    10);
                }

                // bind events to switch icons
                $element.bind('click', function() {
                    savePanelState( panelId, !$scope[panelId] );
                });
            }
        ]
    };

    function savePanelState(id, state) {
        if(!id) return false;
        var data = angular.fromJson(storage[storageKeyName]);
        if(!data) { 
            data = {}; 
        }
        data[id] = state;
        storage[storageKeyName] = angular.toJson(data);
    }

    function loadPanelState(id) {
        if(!id) return false;
        var data = angular.fromJson(storage[storageKeyName]);
        if(data) {
            return data[id];
        }
    }

}])
/**=========================================================
 * Refresh panels
 * [panel-refresh] * [data-spinner="standard"]
 =========================================================*/
.directive('panelRefresh', ["$q", function($q){
    'use strict';
  
    return {
        restrict: 'A',
        scope: false,
        controller: ["$scope", "$element", 
            function ($scope, $element) {
                var refreshEvent   = 'panel-refresh',
                    whirlClass     = 'whirl',
                    defaultSpinner = 'standard';

                // catch clicks to toggle panel refresh
                $element.on('click', function () {
                    var $this   = $(this),
                        panel   = $this.parents('.panel').eq(0),
                        spinner = $this.data('spinner') || defaultSpinner;

                    // start showing the spinner
                    panel.addClass(whirlClass + ' ' + spinner);

                    // Emit event when refresh clicked
                    $scope.$emit(refreshEvent, panel.attr('id'));

                });

                // listen to remove spinner
                $scope.$on('removeSpinner', removeSpinner);

                // method to clear the spinner when done
                function removeSpinner (ev, id) {
                    if (!id) return;
                    var newid = id.charAt(0) == '#' ? id : ('#'+id);
                    angular.element(newid).removeClass(whirlClass);
                }
            }
        ]
    };
}]);

/**=========================================================
 * Directive: sidebar.js
 * Wraps the sidebar and handles collapsed state
 =========================================================*/

App.directive('sidebar', ['$rootScope', '$window', 'Utils', 
    function($rootScope, $window, utils) {
        var $win  = $($window);
        var $body = $('body');
        var $scope;
        var $sidebar;
        var currentState = $rootScope.$state.current.name;

        return {
            restrict: 'EA',
            template: '<nav class="sidebar" ng-transclude></nav>',
            transclude: true,
            replace: true,
            link: function(scope, element, attrs) {
            
                $scope   = scope;
                $sidebar = element;

                var eventName = utils.isTouch() ? 'click' : 'mouseenter' ;
                var subNav = $();
                $sidebar.on( eventName, '.nav > li', function() {

                    if( utils.isSidebarCollapsed() || $rootScope.app.layout.asideHover ) {
                        subNav.trigger('mouseleave');
                        subNav = toggleMenuItem( $(this) );

                        // Used to detect click and touch events outside the sidebar          
                        sidebarAddBackdrop();
                    }

                });

                scope.$on('closeSidebarMenu', function() {
                    removeFloatingNav();
                });

                // Normalize state when resize to mobile
                $win.on('resize', function() {
                    if( ! utils.isMobile() )
                    $body.removeClass('aside-toggled');
                });

                // Adjustment on route changes
                $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
                    currentState = toState.name;
                    // Hide sidebar automatically on mobile
                    $('body.aside-toggled').removeClass('aside-toggled');

                    $rootScope.$broadcast('closeSidebarMenu');
                });

                // Allows to close
                if ( angular.isDefined(attrs.sidebarAnyclickClose) ) {

                    $('.wrapper').on('click.sidebar', function(e){
                    // don't check if sidebar not visible
                    if( ! $body.hasClass('aside-toggled')) return;

                    // if not child of sidebar
                    if( ! $(e.target).parents('.aside').length ) {
                        $body.removeClass('aside-toggled');          
                    }

                    });
                }

            }
        };

        function sidebarAddBackdrop() {
            var $backdrop = $('<div/>', { 'class': 'dropdown-backdrop'} );
            $backdrop.insertAfter('.aside-inner').on("click mouseenter", function () {
            removeFloatingNav();
            });
        }

        // Open the collapse sidebar submenu items when on touch devices 
        // - desktop only opens on hover
        function toggleTouchItem($element){
            $element
            .siblings('li')
            .removeClass('open')
            .end()
            .toggleClass('open');
        }

        // Handles hover to open items under collapsed menu
        // ----------------------------------- 
        function toggleMenuItem($listItem) {

            removeFloatingNav();

            var ul = $listItem.children('ul');
            
            if( !ul.length ) return $();
            if( $listItem.hasClass('open') ) {
                toggleTouchItem($listItem);
                return $();
            }

            var $aside = $('.aside');
            var $asideInner = $('.aside-inner'); // for top offset calculation
            // float aside uses extra padding on aside
            var mar = parseInt( $asideInner.css('padding-top'), 0) + parseInt( $aside.css('padding-top'), 0);
            var subNav = ul.clone().appendTo( $aside );
            
            toggleTouchItem($listItem);

            var itemTop = ($listItem.position().top + mar) - $sidebar.scrollTop();
            var vwHeight = $win.height();

            subNav
            .addClass('nav-floating')
            .css({
                position: $scope.app.layout.isFixed ? 'fixed' : 'absolute',
                top:      itemTop,
                bottom:   (subNav.outerHeight(true) + itemTop > vwHeight) ? 0 : 'auto'
            });

            subNav.on('mouseleave', function() {
                toggleTouchItem($listItem);
                subNav.remove();
            });

            return subNav;
        }

        function removeFloatingNav() {
            $('.dropdown-backdrop').remove();
            $('.sidebar-subnav.nav-floating').remove();
            $('.sidebar li.open').removeClass('open');
        }
    }
]);
/**=========================================================
 * Directive: simple-check.js
 =========================================================*/

App.directive('simpleCheck', [
    function() {
        'use strict';
        
        return {
            restrict: 'EA',
            replace: true,
            template: function($element,$attrs){
                var options = $attrs.optionModel;
                var label = $attrs.label;
                
                return '\
                    <div class="control-label checkbox c-checkbox needsclick">\
                        <label class="needsclick" style="font-weight:bold">\
                            <input type="checkbox" value="" class="needsclick" ng-model="checkboxs.' + options + '"/>\
                            <span class="fa fa-check"></span>\
                            ' + label + '\
                        </label>\
                    </div>\
                '
            }
        }
    }
]);

/**=========================================================
 * Directive: simple-radio.js
 =========================================================*/

App.directive('simpleRadio', ['Utils',
    function(utils) {
        'use strict';
        
        return {
            restrict: 'EA',
            replace: true,
            template: function($element,$attrs){
                var optionModel = $attrs.optionModel || 'radioGroup',   
                    name = $attrs.name,
                    ngModel = '$parent.' + (utils.isEmpty($attrs.ngModel) ? ('radios.' + optionModel  + '.currentCheck') : $attrs.ngModel),
                    showName = $attrs.i18n == 'true' ? '{{$translate.instant(radio.name)}}' : '{{::radio.name}}';
                    
                if ($attrs.type == 'button'){
                    return '\
                        <div class="btn-group">\
                            <label class="btn btn-primary" style="padding: 6px" ng-repeat="radio in radios.' + optionModel + '.radioValues" ng-model="' + ngModel + '" uib-btn-radio="radio.value">\
                                ' + showName + '\
                            </label>\
                        </div>\
                        '
                }else{  
                    return '\
                        <label class="radio-inline c-radio" style="margin-left:20px" ng-repeat="radio in radios.' + optionModel + '.radioValues">\
                            <input type="radio" name="' + name + '" value="{{::radio.value}}" ng-checked="{{$first}}" ng-model="' + ngModel + '"/>\
                            <span class="fa fa-check"></span>\
                            ' + showName + '\
                        </label>\
                    '
                }
            }
        }
    }
]);
/**=========================================================
 * Directive: simple-select.js
 =========================================================*/
App.directive('simpleSelect', ['Utils',
    function(utils) {
        'use strict';
        
        return {
            restrict: 'EA',
            replace: true,
            template: function($element,$attrs){
                var options = $attrs.optionModel,
                    ngModel = utils.isEmpty($attrs.ngModel) ? 'selects.' + options + '.selected' : $attrs.ngModel,
                    name = utils.isEmpty($attrs.name) ? '' : ('name="' + $attrs.name + '"'),
                    required = $attrs.required == undefined ? '' : ' required ',
                    minimumInputLength = $attrs.minimumInputLength == undefined ? '3' : $attrs.minimumInputLength,
                    refresh = $attrs.refresh == undefined ? '' : ' refresh="' + options + 'Query($select.search)" minimum-input-length="'+ minimumInputLength + '" refresh-delay=300 ',
                    multiple = $attrs.multiple == undefined ? '' : ($attrs.refresh == undefined ? ' multiple close-on-select="true"' : ' multiple'),
                    selectedValue = $attrs.multiple == undefined ? '{{$select.selected.name}}' : '{{$item.name}}',
                    filter = $attrs.filter == undefined ? ' | filter: $select.search' : $attrs.filter,
                    highlight = $attrs.filter == undefined ? ' | highlight: $select.search' : '',
                    animated = $attrs.multiple == undefined ? 'fadeIn' : 'fadeIn',
                    allowClear = $attrs.allowClear == 'true' ? 'allow-clear="true"' : '',
                    placeholder = utils.isEmpty($attrs.placeholder) ? '' : 'placeholder="' + $attrs.placeholder + '"',
                    divClass = ($attrs.multiple != undefined && $attrs.refresh == undefined) ? 'class="input-group"' : '',
                    selectAllButton = ($attrs.multiple != undefined && $attrs.refresh == undefined) ? '\
                        <span class="input-group-btn">\
                            <button title="选择全部" type="button" ng-click="' + options + 'AllSelected()" class="btn btn-default">\
                                <small>\
                                    <em class="fa fa-check text-muted icon-lg"></em>\
                                </small>\
                            </button>\
                        </span>' : '';
                
                return '\
                    <div ' + divClass + '>\
                        <ui-select reset-search-input="true" ng-model="' + ngModel + '" ' + name + '' + required + multiple + '>\
                            <ui-select-match ' + allowClear + placeholder + '>' + selectedValue + '</ui-select-match>\
                            <ui-select-choices class="animated ' + animated + '"' + refresh + ' repeat="option.value as option in selects.' + options + '.datas ' + filter + '">\
                                <span ng-bind-html="option.name ' + highlight + '"></span>\
                            </ui-select-choices>\
                        </ui-select>' + selectAllButton + '\
                    </div>\
                '
            },
            link: function($scope, $element, $attrs){
                var options = $attrs.optionModel,
                    ngModel = utils.isEmpty($attrs.ngModel) ? 'selects.' + options + '.selected' : $attrs.ngModel;
                if ($attrs.multiple != undefined && $attrs.refresh == undefined){
                    $scope[options + 'AllSelected'] = function(){
                        var datas = [],
                            allDatas = $scope.selects[$attrs.optionModel].datas;
                        for (var i = 0; i < allDatas.length; i++){
                            if (allDatas[i].value != '-1'){
                                datas.push(allDatas[i].value);
                            }
                            utils.setChildValByStr($scope,ngModel,datas);
                        }
                    }
                }
            }
        }
    }
]);

/**=========================================================
 * Module: skycons.js
 * Include any animated weather icon from Skycons
 =========================================================*/

App.directive('skycon', function(){
    'use strict';
    
    return {
        restrict: 'A',
        scope: {
            icon: '='
        },
        link: function($scope, $element, $attrs) {
      
            var skycons = new Skycons({'color': ($attrs.color || 'white')});

            $element.html('<canvas width="' + $attrs.width + '" height="' + $attrs.height + '"></canvas>');
            
            $scope.$watch("icon", 
                function (newVal, oldVal) {
                    var result;
                    if (newVal != undefined){
                        if (newVal == '晴'){
                            result = 'clear-day';
                        }else if (newVal == '多云' || newVal == '阴'){
                            result = 'cloudy';
                        }else if (newVal == '雨夹雪'){
                            result = 'sleet';
                        }else if (newVal.indexOf('雨') >= 0){
                            result = 'rain'
                        }else if (newVal.indexOf('雪') >= 0){
                            result = 'snow'
                        }else if (newVal == '雾' || newVal == '霾'){
                            result = 'fog'
                        }
                    }
                    
                    skycons.add($element.children()[0], result);
                    skycons.play();
                }
            );
        }
    };
});
/**=========================================================
 * Module: sparkline.js
 * SparkLines Mini Charts
 =========================================================*/
 
App.directive('sparkline', ['$timeout', '$window', 'Utils', 
    function($timeout, $window, utils){

        'use strict';

        return {
            restrict: 'EA',
            scope: {
                watchVar: '='
            },
            link: function($scope, $element, $attrs){
                var runSL = function() {
                    initSparLine($element);
                };

                $timeout(runSL);

                $scope.$watch("watchVar", 
                    function (newVal, oldVal) {
                        if (!utils.isEmpty(newVal)){
                            runSL();
                        }
                    }
                );

                if (!utils.isEmpty($attrs.name)){
                    $scope.$parent[$attrs.name] = $element;
                } 
            }
        };

        function initSparLine($element) {
            var options = $element.data();

            options.type = options.type || 'line'; // default chart is bar
            options.disableHiddenCheck = true;

            $element.sparkline('html', options);

            if(options.resize) {
                $(window).resize(function(){
                    $element.sparkline('html', options);
                });
            }
        }

    }
]);

/**=========================================================
 * Directive: toggle-state.js
 * Toggle a classname from the BODY Useful to change a state that 
 * affects globally the entire layout or more than one item 
 * Targeted elements must have [toggle-state="CLASS-NAME-TO-TOGGLE"]
 * User no-persist to avoid saving the sate in browser storage
 =========================================================*/

App.directive('toggleState', ['toggleStateService', function(toggle) {
    'use strict';
    
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var $body = $('body');

            $(element).on('click', function (e) {
                e.preventDefault();
                var classname = attrs.toggleState;
                
                if(classname) {
                    if($body.hasClass(classname)) {
                        $body.removeClass(classname);
                        if(!attrs.noPersist)
                            toggle.removeState(classname);
                    }else {
                        $body.addClass(classname);
                        if(!attrs.noPersist)
                            toggle.addState(classname);
                    }    
                }
            });
        }
    };
  
}]);

/**=========================================================
 * Directive: ztree.js
 * Initializes the ztree plugin
 =========================================================*/

App.directive('ztree', ['Utils',
    function(utils) {
        'use strict';
        
        return {
            restrict: 'EA',
            replace: true,
            template: function($element,$attrs) {
                return '<ul id="tree' + (Math.random() * 1000).toFixed(0) + '" class="ztree"></ul>'
            },
            scope: {
                option: '='
            },
            link: function ($scope, $element, $attrs) {
                //监听option变化
                $scope.$watch("option", 
                    function (newVal, oldVal) {
                        if (!utils.isEmpty(newVal)){
                            var scope = $scope.$parent;
                            if (!utils.isEmpty($attrs.level)){
                                for (var i = 1; i < $attrs.level; i++){
                                    scope = scope.$parent;
                                }
                            }
                            scope[newVal.name] = $.fn.zTree.init($element, newVal.setting, newVal.data);
                        }
                    }
                );            
            }
        }
    }
]);
/**=========================================================
 * Service: browser.js
 * Browser detection
 =========================================================*/

App.service('browser', function(){
  "use strict";

  var matched, browser;

  var uaMatch = function( ua ) {
      ua = ua.toLowerCase();

      var match = /(opr)[\/]([\w.]+)/.exec( ua ) ||
        /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
        /(version)[ \/]([\w.]+).*(safari)[ \/]([\w.]+)/.exec( ua ) ||
        /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
        /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
        /(msie) ([\w.]+)/.exec( ua ) ||
        ua.indexOf("trident") >= 0 && /(rv)(?::| )([\w.]+)/.exec( ua ) ||
        ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
        [];

      var platform_match = /(ipad)/.exec( ua ) ||
        /(iphone)/.exec( ua ) ||
        /(android)/.exec( ua ) ||
        /(windows phone)/.exec( ua ) ||
        /(win)/.exec( ua ) ||
        /(mac)/.exec( ua ) ||
        /(linux)/.exec( ua ) ||
        /(cros)/i.exec( ua ) ||
        [];

      return {
          browser: match[ 3 ] || match[ 1 ] || "",
          version: match[ 2 ] || "0",
          platform: platform_match[ 0 ] || ""
      };
  };

  matched = uaMatch( window.navigator.userAgent );
  browser = {};

  if ( matched.browser ) {
      browser[ matched.browser ] = true;
      browser.version = matched.version;
      browser.versionNumber = parseInt(matched.version);
  }

  if ( matched.platform ) {
      browser[ matched.platform ] = true;
  }

  // These are all considered mobile platforms, meaning they run a mobile browser
  if ( browser.android || browser.ipad || browser.iphone || browser[ "windows phone" ] ) {
      browser.mobile = true;
  }

  // These are all considered desktop platforms, meaning they run a desktop browser
  if ( browser.cros || browser.mac || browser.linux || browser.win ) {
      browser.desktop = true;
  }

  // Chrome, Opera 15+ and Safari are webkit based browsers
  if ( browser.chrome || browser.opr || browser.safari ) {
      browser.webkit = true;
  }

  // IE11 has a new token so we will assign it msie to avoid breaking changes
  if ( browser.rv )
  {
      var ie = "msie";

      matched.browser = ie;
      browser[ie] = true;
  }

  // Opera 15+ are identified as opr
  if ( browser.opr )
  {
      var opera = "opera";

      matched.browser = opera;
      browser[opera] = true;
  }

  // Stock Android browsers are marked as Safari on Android.
  if ( browser.safari && browser.android )
  {
      var android = "android";

      matched.browser = android;
      browser[android] = true;
  }

  // Assign the name and platform variable
  browser.name = matched.browser;
  browser.platform = matched.platform;


  return browser;

});
/**=========================================================
 * Service: colors.js
 * Services to retrieve global colors
 =========================================================*/
 
App.factory('colors', ['APP_COLORS', 
    function(colors) {
        return {
            byName: function(name) {
                return (colors[name] || '#fff');
            }
        };
    }
]);

/**=========================================================
 * Service: DialogUtils.js
 =========================================================*/

App.service('DialogUtils', ['ngDialog',
    function(ngDialog) {
        'use strict';        
        return {
            alert: function(content) {
                ngDialog.openConfirm({
                    plain: true,
                    template: '\
                        <p>' + content + '</p>\
                        <div class="ngdialog-buttons">\
                            <button type="button" class="ngdialog-button ngdialog-button-primary" ng-click="closeThisDialog()">确定</button>\
                        </div>'
                });
            },
            confirm: function(content,confirmFn,cancelFn) {
                ngDialog.openConfirm({
                plain: true,
                template: '\
                        <p>' + content + '</p>\
                        <div class="ngdialog-buttons">\
                            <button type="button" class="ngdialog-button ngdialog-button-secondary" ng-click="closeThisDialog()">取消</button>\
                            <button type="button" class="ngdialog-button ngdialog-button-primary" ng-click="confirm()">继续</button>\
                        </div>'
                }).then(confirmFn,cancelFn);
            }
        };
    }
]);
/**=========================================================
 * Service: httpUtils.js
 * Utility library to use across the theme
 =========================================================*/

App.service('HttpUtils', ["$rootScope", "$http", '$q', "Utils",
    function($rootScope, $http, $q, utils) {
        'use strict';
                  
        return {
            queryList: function(params,successFn,failureFn){
                this.get('/common/queryList',params,successFn,failureFn);
            },
            get: function(path,params,successFn,failureFn) {
                //get方法中文乱码
                this.post(path,params,successFn,failureFn);
            },
            post: function(path,params,successFn,failureFn) {
                if ($rootScope.app.isSessionValid){
                    if (utils.isEmpty(failureFn)){
                        failureFn = function(){};
                    }
                    $http({
                        url: utils.getBackendPath(path),
                        method: 'POST',
                        timeout: 60000,
						withCredentials: true, // 跨域
                        headers: {'Content-Type': 'application/x-www-form-urlencoded;charset=utf8'},
                        transformRequest: function(obj) {
                            var str = [];
                            for(var p in obj)
                            str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
                            return str.join("&");
                        },
                        data: params
                    }).then(function(response){
                        var result = response.data;
                        if (result.isValid == 'false'){
                            if($rootScope.$state.current.name != 'page.login'){
                                //第一次发现session过期
                                $rootScope.app.user = {};
                                $rootScope.app.isSessionValid = false;
                                $rootScope.stateToGo = $rootScope.$state.current.name;
                                $rootScope.$state.go('page.login');
                            }
                            return;
                        }
                        if (!utils.isEmpty(successFn))
                            successFn.call(this,result);
                    }).catch(failureFn);
                }else{
                    console.log('Invalid Session')
                } 
            },
            promise: function(path,params){
                var deferred = $q.defer();
                $http.get(utils.getBackendPath(path),{withCredentials: true}).then(
                    function(result) {
                        deferred.resolve(result);
                    },
                    function(data, status, headers, config) {
                        deferred.reject(data);
                    }
                );
                return deferred.promise;
            }
        };
    }
]);
/**=========================================================
 * Service: nav-search.js
 * Services to share navbar search functions
 =========================================================*/
 
App.service('navSearch', function() {
  var navbarFormSelector = 'form.navbar-form';
  return {
    toggle: function() {
      
      var navbarForm = $(navbarFormSelector);

      navbarForm.toggleClass('open');
      
      var isOpen = navbarForm.hasClass('open');
      
      navbarForm.find('input')[isOpen ? 'focus' : 'blur']();

    },

    dismiss: function() {
      $(navbarFormSelector)
        .removeClass('open')      // Close control
        .find('input[type="text"]').blur() // remove focus
        .val('')                    // Empty input
        ;
    }
  };

});
/**=========================================================
 * Service: route-helpers.js
 * Provides helper functions for routes definition
 =========================================================*/

App.provider('RouteHelpers', ['APP_REQUIRES', function (appRequires) {
    "use strict";

    // Set here the base of the relative path
    // for all app views
    this.basepath = function(uri) {
        return 'app/views/' + uri + "?_t=" + (new Date()).valueOf();
    };

    // Generates a resolve object by passing script names
    // previously configured in constant.APP_REQUIRES
    this.resolveFor = function() {
        var _args = arguments;
        return {
        deps: ['$ocLazyLoad','$q', function ($ocLL, $q) {
            // Creates a promise chain for each argument
            var promise = $q.when(1); // empty promise
            for(var i=0, len=_args.length; i < len; i ++){
                promise = andThen(_args[i]);
            }
            return promise;

            // creates promise to chain dynamically
            function andThen(_arg) {
                // also support a function that returns a promise
                if(typeof _arg == 'function')
                    return promise.then(_arg);
                else
                    return promise.then(function() {
                        // if is a module, pass the name. If not, pass the array
                        var whatToLoad = getRequired(_arg);
                        // simple error check
                        if(!whatToLoad) return $.error('Route resolve: Bad resource name [' + _arg + ']');
                        // finally, return a promise
                        return $ocLL.load( whatToLoad );
                    });
            }
            // check and returns required data
            // analyze module items with the form [name: '', files: []]
            // and also simple array of script files (for not angular js)
            function getRequired(name) {
                if (appRequires.modules)
                    for(var m in appRequires.modules)
                        if(appRequires.modules[m].name && appRequires.modules[m].name === name)
                            return appRequires.modules[m];
                return appRequires.scripts && appRequires.scripts[name];
            }

        }]};
    }; // resolveFor

    // not necessary, only used in config block for routes
    this.$get = function(){};

}]);


/**=========================================================
 * Service: toggle-state.js
 * Services to share toggle state functionality
 =========================================================*/

App.service('toggleStateService', ['$rootScope', function($rootScope) {

    var storageKeyName  = 'toggleState';

    // Helper object to check for words in a phrase //
    var WordChecker = {
        hasWord: function (phrase, word) {
            return new RegExp('(^|\\s)' + word + '(\\s|$)').test(phrase);
        },
        addWord: function (phrase, word) {
            if (!this.hasWord(phrase, word)) {
                return (phrase + (phrase ? ' ' : '') + word);
            }
        },
        removeWord: function (phrase, word) {
            if (this.hasWord(phrase, word)) {
                return phrase.replace(new RegExp('(^|\\s)*' + word + '(\\s|$)*', 'g'), '');
            }
        }
    };

    // Return service public methods
    return {
        // Add a state to the browser storage to be restored later
        addState: function(classname){
            var data = angular.fromJson($rootScope.$storage[storageKeyName]);
            
            if(!data)  {
                data = classname;
            }else {
                data = WordChecker.addWord(data, classname);
            }

            $rootScope.$storage[storageKeyName] = angular.toJson(data);
        },

        // Remove a state from the browser storage
        removeState: function(classname){
            var data = $rootScope.$storage[storageKeyName];
            // nothing to remove
            if(!data) return;

            data = WordChecker.removeWord(data, classname);

            $rootScope.$storage[storageKeyName] = angular.toJson(data);
        },
        
        // Load the state string and restore the classlist
        restoreState: function($elem) {
            var data = angular.fromJson($rootScope.$storage[storageKeyName]);
            
            // nothing to restore
            if(!data) return;
            $elem.addClass(data);
        }
    };
}]);
/**=========================================================
 * Service: utils.js
 * Utility library to use across the theme
 =========================================================*/

App.service('Utils', ["$window", "APP_MEDIAQUERY", "BACKEND_PATH", 
    function($window, APP_MEDIAQUERY, BACKEND_PATH) {
        'use strict';
        
        var $html = angular.element("html"),
            $win  = angular.element($window),
            $body = angular.element('body');
            
        return {
            // DETECTION
            support: {
                transition: (function() {
                    var transitionEnd = (function() {

                        var element = document.body || document.documentElement,
                            transEndEventNames = {
                                WebkitTransition: 'webkitTransitionEnd',
                                MozTransition: 'transitionend',
                                OTransition: 'oTransitionEnd otransitionend',
                                transition: 'transitionend'
                            }, name;

                        for (name in transEndEventNames) {
                            if (element.style[name] !== undefined) return transEndEventNames[name];
                        }
                    }());

                    return transitionEnd && { end: transitionEnd };
                })(),
                animation: (function() {
                    var animationEnd = (function() {
                        var element = document.body || document.documentElement,
                            animEndEventNames = {
                                WebkitAnimation: 'webkitAnimationEnd',
                                MozAnimation: 'animationend',
                                OAnimation: 'oAnimationEnd oanimationend',
                                animation: 'animationend'
                            }, name;

                        for (name in animEndEventNames) {
                            if (element.style[name] !== undefined) return animEndEventNames[name];
                        }
                    }());

                    return animationEnd && { end: animationEnd };
                })(),
                requestAnimationFrame: window.requestAnimationFrame ||
                                    window.webkitRequestAnimationFrame ||
                                    window.mozRequestAnimationFrame ||
                                    window.msRequestAnimationFrame ||
                                    window.oRequestAnimationFrame ||
                                    function(callback){ 
                                        window.setTimeout(callback, 1000/60); 
                                    },
                touch: (
                    ('ontouchstart' in window && navigator.userAgent.toLowerCase().match(/mobile|tablet/)) ||
                    (window.DocumentTouch && document instanceof window.DocumentTouch)  ||
                    (window.navigator['msPointerEnabled'] && window.navigator['msMaxTouchPoints'] > 0) || //IE 10
                    (window.navigator['pointerEnabled'] && window.navigator['maxTouchPoints'] > 0) || //IE >=11
                    false
                ),
                mutationobserver: (window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver || null)
            },
            // UTILITIES
            isInView: function(element, options) {

                var $element = $(element);

                if (!$element.is(':visible')) {
                    return false;
                }

                var window_left = $win.scrollLeft(),
                    window_top  = $win.scrollTop(),
                    offset      = $element.offset(),
                    left        = offset.left,
                    top         = offset.top;

                options = $.extend({topoffset:0, leftoffset:0}, options);

                if (top + $element.height() >= window_top && top - options.topoffset <= window_top + $win.height() &&
                    left + $element.width() >= window_left && left - options.leftoffset <= window_left + $win.width()) {
                    return true;
                } else {
                    return false;
                }
            },
            
            langdirection: $html.attr("dir") == "rtl" ? "right" : "left",
            
            isTouch: function () {
                return $html.hasClass('touch');
            },
            
            isSidebarCollapsed: function () {
                return $body.hasClass('aside-collapsed');
            },
            
            isSidebarToggled: function () {
                return $body.hasClass('aside-toggled');
            },
            
            isMobile: function () {
                return $win.width() < APP_MEDIAQUERY.tablet;
            },
            
//==============================================通用操作======================================================      
            /**
             * 获取后台请求地址
             */  
            getBackendPath: function(relativePath){
                return BACKEND_PATH + relativePath;
            },

            /**
             * 获取非分页查询的相对路径
             */
            getQueryListUrl: function(){
                return '/common/queryList'
            },
            
            /**
             * 获取分页查询的相对路径
             */
            getQueryPageUrl: function(){
                return '/common/queryPage'
            },
              
            /**
             * 判定是否为空
             */   
            isEmpty: function(obj){
                return obj == null || obj === "" || obj === 'undefined' || obj === undefined || obj.length === 0;
            },

            /**
             * 返回第一个非空值
             */ 
            coalesce: function(){
                for (var i = 0; i < arguments.length; i++) {
                    if (!this.isEmpty(arguments[i]))
                        return arguments[i];
                }
            },
            
            /**
             * 判定是否为年、年月或年月日
             */   
            isTimeStr: function(str){
                var reg1 = /\d{4}-\d{2}-\d{2}/,
                    reg2 = /\d{4}-\d{2}/,                
                    reg3 = /[A-Za-z]{3}.\d{4}/;
                return reg1.test(str) || reg2.test(str) || reg3.test(str);
            },
            
            getLanguage: function(){
                return localStorage.NG_TRANSLATE_LANG_KEY;
            },
            
            clone: function(obj) {
                if (typeof obj == "function" || Object(obj) !== obj) {
                    return obj;
                }
                
                var res = new obj.constructor;
                
                for (var key in obj) {
                    res[key] = this.clone(obj[key]);
                }
                return res;
            },

            setChildValByStr: function(obj,path,value){
                var paths = path.split("."),
                    level = paths.length;
                switch(level) {
                    case 1:
                        obj[paths[0]] = value;
                        break;
                    case 2:
                        obj[paths[0]][paths[1]] = value;
                        break;
                    case 3:
                        obj[paths[0]][paths[1]][paths[2]] = value;
                        break;
                    case 4:
                        obj[paths[0]][paths[1]][paths[2]][paths[3]] = value;
                        break;
                    case 5:
                        obj[paths[0]][paths[1]][paths[2]][paths[3]][paths[4]] = value;
                        break;
                }
            },
//==============================================数字操作======================================================
            /**
             * 增加千分位符
             */
            numberFormat: function(value){
                if (this.isEmpty(value)) return value;
                
                var intValue, decValue, symbol = '', result = '',
                    strValue = value.toString();
                
                if (strValue.indexOf('-') > -1){
                    symbol = '-';
                    strValue = strValue.substring(1,strValue.length);
                }
                
                if (strValue.indexOf('.') > -1) {
                    intValue = strValue.substring(0,strValue.indexOf('.'));
                    decValue = strValue.substring(strValue.indexOf('.'))
                } else{
                    intValue = strValue;
                    decValue = '';
                }
                while (intValue.length > 3) {
                    result = ',' + intValue.slice(-3) + result;
                    intValue = intValue.slice(0, intValue.length - 3);
                } 
                
                result = symbol + intValue + result + decValue; 
                
                return result;
            },         
//==============================================时间操作======================================================    
            /**
             * 判定日期字符串
             */  
            isDateString: function(str){			
                var date = /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/,	
                    month = /^[0-9]{4}-[0-9]{2}$/,	
                    year = /^[0-9]{4}$/;	
                return date.test(str) || month.test(str) || year.test(str);
            },
            
            /**
             *  日期格式化 
             */      
            dateFormat: function(date,format){
                if (date instanceof Date){
                    var o = {   
                        "M+" : date.getMonth() + 1,                 //月份   
                        "d+" : date.getDate(),                    //日   
                        "h+" : date.getHours(),                   //小时   
                        "m+" : date.getMinutes(),                 //分   
                        "s+" : date.getSeconds(),                 //秒   
                        "q+" : Math.floor((date.getMonth() + 3) / 3), //季度   
                        "S"  : date.getMilliseconds()             //毫秒   
                    };   
                    if(/(y+)/.test(format))   
                        format = format.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));   
                    for(var k in o){
                        if(new RegExp("("+ k +")").test(format)){
                            format = format.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
                        }
                    }
                    return format;
                }else{
                    return date;
                }
            },
            
            /**
             *  判断闰年
             */
            isLeapYear: function(date) {
                var year = date.getFullYear();
                return !!((year & 3) === 0 && (year % 100 || (year % 400 === 0 && year)));
            },
            
            /**
             *  日期的加减操作
             */
            addDate: function(date, interval, value){
                var returnDate = new Date(date.getTime());
                if (value) {
                    switch(interval.toLowerCase()) {
                        case 'second':
                            returnDate.setTime(date.getTime() + value * 1000);
                            break;
                        case 'minute':
                            returnDate.setTime(date.getTime() + value * 60 * 1000);
                            break;
                        case 'hour':
                            returnDate.setTime(date.getTime() + value * 60 * 60 * 1000);
                            break;
                        case 'day':
                            returnDate.setDate(date.getDate() + value);
                            break;
                        case 'month':
                            returnDate.setMonth(date.getMonth() + value);
                            break;
                        case 'year':
                            returnDate.setFullYear(date.getFullYear() + value);
                            break;
                    }
                }

                return returnDate;
            },

            /**
             *  获取日期的季度
             */
            getQuarter: function(date){
                var month = date.getMonth() + 1;
                if(month <= 3) return 1
                else if (month <= 6) return 2
                else if (month <= 9) return 3
                else return 4
            },
            
            /**
             * 将字符型转成Date型
             */
            strToDate: function(dateStr,format){
                var dateParseStr;
                if (format == 'yyyy-MM-dd'){
                    dateParseStr = dateStr.replace(/-/g, "/");
                }else if (format == 'yyyyMMdd'){
                    dateParseStr = dateStr.substr(0,4) + '/' + dateStr.substr(4,2) + '/' + dateStr.substr(6,2);
                }
                return new Date(Date.parse(dateParseStr));
            },

            /**
             * 获取一周的第一天 即周六
             */
            getStartDayOfWeek: function(date){
                return date.getDay() == 6 ? date : this.addDate(date,'day',(date.getDay() + 1) * -1);
            },
//================================================数组操作============================================ 
            /**
             *  合并数组
             */           
            mergeArray: function(array1, array2, etc){
                var array = []

                for (var i = 0; i < arguments.length; i++) {
                    array = array.concat(arguments[i]);
                }
                
                return array;     
            },
            
            /**
             * 从数组中删除
             */
            removeFromArray: function(array,target,key){
                if (angular.isObject(target)){
                    for (var i = 0; i < array.length; i++){
                        if (array[i][key] === target[key]){
                            array.splice(i, 1);
                        }
                    }
                }else{
                    for (var i = 0; i < array.length; i++){
                        if (array[i] === target){
                            array.splice(i, 1);
                        }
                    }
                }
            },
            
            /**
             * 数组转化成字符串
             */
            arrayToString: function(array,separate){
                var result = "";
                if (!this.isEmpty(array)){
                    
                    if (this.isEmpty(separate)){
                        separate = ",";
                    }
                    
                    for (var i = 0; i < array.length; i++){
                        result += array[i] + separate;
                    }
                    return result.substring(0,result.length - 1);
                }

                return result;
            },
            
            /**
             * 数组中是否包含
             */
            isArrayContains: function(array,obj){
                if (this.isEmpty(array)){
                    return false;
                }
                
                for (var i = 0; i < array.length; i++){
                    if (array[i] == obj){
                        return true;
                    }
                }
                
                return false;
            },

//================================================表格操作============================================ 
            /**
             * 行合并
             */
            handleRowspan: function(column,datas){
                if (this.isEmpty(datas) || datas.length < 0) return datas;

                var index = 0;
                datas[0][column + "_rowSpan"] = 1;
                for (var i = 1; i < datas.length; i++){
                    if (datas[i][column] == datas[index][column]){
                        datas[index][column + "_rowSpan"] = datas[index][column + "_rowSpan"] + 1;
                        datas[i][column + "_rowSpan"] = -1;
                    }else{
                        datas[i][column + "_rowSpan"] = 1;
                        index = i;
                    }
                }

                return datas;
            }   
        };
    }
]);
/**=========================================================
 * Service: datepicker-range.js
 =========================================================*/

App.service('DatepickerRange', ['Utils',
    function(utils) {
        'use strict';
        
        return {
            init: function($scope, options) {
                var defaultOptions = {
                    optionModel: 'dateRange',
                    startDate: utils.addDate(new Date(), "day", -7),
                    endDate: utils.addDate(new Date(), "day", -1)
                }
                
                var finalOptions = angular.extend(defaultOptions,options)
                
                if (utils.isEmpty($scope.rangeDatePickers)){
                    $scope.rangeDatePickers = {}
                }
                
                $scope.rangeDatePickers[finalOptions.optionModel] = {};
                //开始日期
                $scope.rangeDatePickers[finalOptions.optionModel].startDate = {
                    date: finalOptions.startDate,
                    dateOptions: {
                        startingDay: 1,
                        maxDate: finalOptions.endDate
                    },
                    opened: false
                };
                //结束日期
                $scope.rangeDatePickers[finalOptions.optionModel].endDate = {
                    date: finalOptions.endDate,
                    dateOptions: {
                        startingDay: 1,
                        minDate: finalOptions.startDate
                    },
                    opened: false
                }
                
                return {
                    scope: $scope,
                    options: finalOptions,
                    addParam: function(params,format){
                        if (utils.isEmpty(format)){
                            format = 'yyyyMMdd';
                        }
                        params.startDate = utils.dateFormat(new Date($scope.rangeDatePickers[this.options.optionModel].startDate.date),format);
                        params.endDate = utils.dateFormat(new Date($scope.rangeDatePickers[this.options.optionModel].endDate.date),format);
                    },
                    getStartDate: function(){
                        return new Date($scope.rangeDatePickers[this.options.optionModel].startDate.date);
                    },
                    getEndDate: function(){
                        return new Date($scope.rangeDatePickers[this.options.optionModel].endDate.date);
                    }
                }
            }
        }
    }
]);

/**=========================================================
 * Service: datepicker.js
 =========================================================*/

App.service('Datepicker', ['Utils',
    function(utils) {
        'use strict';
        
        return {
            init: function($scope, options) {
                var defaultOptions = {
                    optionModel: 'date', 
                    initValue: utils.addDate(new Date(), "day", -1)
                }
                
                var finalOptions = utils.isEmpty(options) ? defaultOptions : angular.extend(defaultOptions,options);
                
                if (utils.isEmpty($scope.datepickers)) {
                    $scope.datepickers = {}
                }
                 
                $scope.datepickers[finalOptions.optionModel] = {
                    date: finalOptions.initValue,
                    dateOptions: {
                        startingDay: 1 
                    },
                    opened: false
                };
                return {
                    scope: $scope,
                    options: finalOptions,
                    getDate: function(){
                        return $scope.datepickers[this.options.optionModel].date;
                    },
                    setDate: function(newVal){
                        $scope.datepickers[this.options.optionModel].date = newVal;
                    }
                }
            }
        }
    }
]);

/**=========================================================
 * Service: double-select.js
 =========================================================*/

App.service('DoubleSelect', ["$timeout", 'Utils', 'HttpUtils', 'SimpleSelect',
    function($timeout, utils, httpUtils, simpleSelectService) {
        'use strict';
        
        return {
            init: function($scope, options) {
                var defaultOptions = {
                    /**
                     * $scope.selects对象中的属性名
                     */
                    optionModel: '',
                    /**
                     * 后台的查询参数
                     */
                    params: '',
                    /**
                     * 是否请求后台
                     */
                    remote: true,
                    /**
                     * 本地数据
                     */
                    datas: []
                }
                
                var finalOptions = angular.extend(defaultOptions,options);
                
                if (utils.isEmpty($scope.doubleSelects)) {
                    $scope.doubleSelects = {};
                }
                
                $scope.doubleSelects[finalOptions.optionModel] = {};
                
                var simpleSelect = simpleSelectService.init($scope,
                    {
                        optionModel: finalOptions.optionModel,
                        multiple: true,
                        params: finalOptions.params,
                        remote: finalOptions.remote,
                        datas: finalOptions.datas
                    }
                );
                
                $scope.$watch('doubleSelects.' + finalOptions.optionModel + '.selected1', 
                    function (newVal, oldVal) {
                        if (newVal != undefined){
                            $timeout(function(){
                                simpleSelect.clearFilter();
                                if (utils.isEmpty($scope.doubleSelects[finalOptions.optionModel].selected2)){
                                    simpleSelect.filter('value',newVal,'!=');
                                }else{                   
                                    simpleSelect.filter('value',utils.mergeArray(newVal,$scope.doubleSelects[finalOptions.optionModel].selected2),'!=');
                                }
                            });
                        }
                    }
                );
                
                $scope.$watch('doubleSelects.' + finalOptions.optionModel + '.selected2', 
                    function (newVal, oldVal) {
                        if (newVal != undefined){
                            $timeout(function(){
                                simpleSelect.clearFilter();
                                if (utils.isEmpty($scope.doubleSelects[finalOptions.optionModel].selected1)){
                                    simpleSelect.filter('value',newVal,'!=');
                                }else{                   
                                    simpleSelect.filter('value',utils.mergeArray(newVal,$scope.doubleSelects[finalOptions.optionModel].selected1),'!=');
                                }
                            });
                        }    
                    }
                );
                
                return {
                    scope: $scope,
                    options: finalOptions,
                    simpleSelect: simpleSelect,
                    /**
                     * 获取选中值
                     */
                    getSelected: function(){
                        return [this.scope.doubleSelects[this.options.optionModel].selected1,this.scope.doubleSelects[this.options.optionModel].selected2];
                    },
                    /**
                     * 选中指定值
                     * index:1或2
                     */
                    select: function(newVal,index){
                        this.simpleSelect.clearFilter();
                        this.scope.doubleSelects[this.options.optionModel]["selected" + index] = [newVal];
                    },
                    clear: function(index){
                        this.scope.doubleSelects[this.options.optionModel]["selected" + index] = [];
                    }
                };
            }
        }
    }
]);

/**=========================================================
 * Service: simple-check.js
 =========================================================*/

App.service('SimpleCheck', ['Utils',
    function(utils) {
        'use strict';
        
        return {
            init: function($scope,options) {
                var defaultOptions = {
                    optionModel: '',
                    initValue: false,
                    checkChangeEvent: null
                }
                
                var finalOptions = angular.extend(defaultOptions,options)
                
                if (utils.isEmpty($scope.checkboxs)) {
                    $scope.checkboxs = {}
                }
                
                $scope.checkboxs[finalOptions.optionModel] = finalOptions.initValue;
                
                if (options.checkChangeEvent instanceof Function) {
                    finalOptions.checkChangeEvent = options.checkChangeEvent;
                    $scope.$watch('checkboxs.' + finalOptions.optionModel, 
                        function (newVal, oldVal) { 
                            if (newVal != oldVal){
                                options.checkChangeEvent.call();
                            }
                        }
                    );
                }

                return {
                    scope: $scope,
                    options: finalOptions,
                    getCheck: function(){
                        var options = this.options;
                        var scope = this.scope;
                        return scope.checkboxs[options.optionModel];
                    }
                }
            }
        }
    }
]);
/**=========================================================
 * Service: simple-radio.js
 =========================================================*/

App.service('SimpleRadio', ['HttpUtils','Utils',
    function(httpUtils, utils) {
        'use strict';
        
        return {
            /**
             * 数据格式
             * name:名称
             * value:值
             */
            init: function($scope,options) {
                var defaultOptions = {
                    /**
                     * $scope对象中的属性名
                     */
                    optionModel: 'radioGroup',
                    /**
                     * 选中值实际绑定的变量名
                     * 如果绑定了自定义的变量 并且需要触发值变更事件时 需要指定
                     */
                    ngModel: '',
                    /**
                    /**
                     * 后台的查询参数
                     */
                    params: {},
                    /**
                     * 是否请求后台
                     */
                    remote: true,
                    /**
                     * 本地数据
                     * {name: 'name', value: 'value'}
                     */
                    datas: [],
                    /**
                     * 初始值
                     */
                    initValue: '',
                    /**
                     * 值变更事件
                     */
                    checkChangeEvent: null
                }
                
                var finalOptions = angular.extend(defaultOptions,options)
                
                if (utils.isEmpty($scope.radios)){
                    $scope.radios = {};
                }
                $scope.radios[finalOptions.optionModel] = {
                    currentCheck: '',
                    radioValues: []
                };
                
                //事件
                if (finalOptions.checkChangeEvent instanceof Function) {
                    var variable = utils.isEmpty(finalOptions.ngModel) ? 'radios.' + finalOptions.optionModel + ".currentCheck" : finalOptions.ngModel;
                    $scope.$watch(variable, 
                        function (newVal, oldVal) {
                            finalOptions.checkChangeEvent.call(this,newVal,oldVal);
                        }
                    );
                }
                
                //数据
                if (finalOptions.remote){
                    httpUtils.get(utils.getQueryListUrl(),finalOptions.params,
                        function (result) {
                            var datas = result.datas.gridDatas;
                            if (utils.isEmpty(finalOptions.initValue)){
                                $scope.radios[finalOptions.optionModel].currentCheck = datas[0].value;
                            }else{
                                $scope.radios[finalOptions.optionModel].currentCheck = finalOptions.initValue;
                            }
                            
                            for (var i = 0; i < datas.length; i++){
                                $scope.radios[finalOptions.optionModel].radioValues.push({name: datas[i].name, value: datas[i].value})
                            }
                        }
                    );
                }else{
                    $scope.radios[finalOptions.optionModel].radioValues = finalOptions.datas;
                
                    if (utils.isEmpty(finalOptions.initValue)){
                        $scope.radios[finalOptions.optionModel].currentCheck = finalOptions.datas[0].value;
                    }else{
                        $scope.radios[finalOptions.optionModel].currentCheck = finalOptions.initValue;
                    }
                }
                


                return {
                    scope: $scope,
                    options: finalOptions,
                    getCurrentCheck: function(){
                        var options = this.options;
                        var scope = this.scope;
                        return $scope.radios[finalOptions.optionModel].currentCheck;
                    }
                }
            }
        }
    }
]);
/**=========================================================
 * Service: simple-select.js
 =========================================================*/

App.service('SimpleSelect', ['Utils', 'HttpUtils',
    function(utils, httpUtils) {
        'use strict';
        
        return {
            init: function($scope, options) {
                var defaultOptions = {
                    /**
                     * $scope.selects对象中的属性名
                     */
                    optionModel: '',
                    /**
                     * 选中值实际绑定的变量名
                     * 如果绑定了自定义的变量 并且需要触发值变更事件时 需要指定
                     */
                    ngModel: '',
                    /**
                     * 后台的查询参数
                     */
                    params: '',
                    /**
                     * 是否请求后台
                     */
                    remote: true,
                    /**
                     * 是否实时刷新
                     */
                    refresh: false,
                    /**
                     * 本地数据
                     * {name: 'name', value: 'value'}
                     */
                    datas: [],
                    /**
                     * 是否多选
                     */
                    multiple: false,
                    /**
                     * 初始值
                     */
                    initValue: '',
                    /**
                     * 初始名称
                     */
                    initName: '',
                    /**
                     * 初始过滤条件
                     * {attr:'filter',value:'-9999'}
                     */
                    initFilter: null,
                    /**
                     * 值变更事件
                     */
                    selectChangeEvent: null,
                    /**
                     * 是否自动加载
                     */
                    autoLoad: true,
                    /**
                     * 是否默认选择第一个
                     */
                    autoSelect: false
                }
                
                var finalOptions = angular.extend(defaultOptions,options);
                if (finalOptions.multiple && utils.isEmpty(finalOptions.initValue)){
                    finalOptions.initValue = [];
                }
                
                if (utils.isEmpty($scope.selects)) {
                    $scope.selects = {};
                }
                
                $scope.selects[finalOptions.optionModel] = {};
                
                if (finalOptions.refresh){
                    $scope.selects[finalOptions.optionModel].selected = finalOptions.initValue;
                    $scope[finalOptions.optionModel + "Query"] = function(inputValue){
                        finalOptions.params.inputValue = inputValue;
                        if (!utils.isEmpty(inputValue)){
                            httpUtils.queryList(finalOptions.params,
                                function(result){
                                    var allDatas = result.datas.gridDatas;
                                    
                                    for (var i = 0; i < allDatas.length; i++){
                                        allDatas[i].value = allDatas[i].value + "";
                                    }
                                    
                                    $scope.selects[finalOptions.optionModel].allDatas = allDatas;
                                    
                                    if (utils.isEmpty(finalOptions.initFilter)){
                                        $scope.selects[finalOptions.optionModel].datas = allDatas;
                                    }else{
                                        var datas = [];
                                        for (var i = 0; i < allDatas.length; i++){
                                            if (allDatas[i][finalOptions.initFilter.attr] == finalOptions.initFilter.value){
                                                datas.push(utils.clone(allDatas[i]));
                                            }
                                        }
                                        
                                        $scope.selects[finalOptions.optionModel].datas = datas;
                                    }
                                }
                            );
                        }else{
                            $scope.selects[finalOptions.optionModel].allDatas = [];
                            $scope.selects[finalOptions.optionModel].datas = [];
                        }
                    }
                }else if (finalOptions.autoLoad) {
                    //获取数据
                    if (finalOptions.remote){
                        httpUtils.queryList(finalOptions.params,
                            function(result){
                                var allDatas = result.datas.gridDatas;
                                
                                for (var i = 0; i < allDatas.length; i++){
                                    allDatas[i].value = allDatas[i].value + "";
                                }
                                
                                $scope.selects[finalOptions.optionModel].allDatas = allDatas;
                                
                                if (utils.isEmpty(finalOptions.initFilter)){
                                    $scope.selects[finalOptions.optionModel].datas = allDatas;
                                }else{
                                    var datas = [];
                                    for (var i = 0; i < allDatas.length; i++){
                                        if (allDatas[i][finalOptions.initFilter.attr] == finalOptions.initFilter.value){
                                            datas.push(utils.clone(allDatas[i]));
                                        }
                                    }
                                    
                                    $scope.selects[finalOptions.optionModel].datas = datas;
                                }

                                if (finalOptions.autoSelect){
                                    $scope.selects[finalOptions.optionModel].selected =  $scope.selects[finalOptions.optionModel].datas[0].value;
                                }   
                            }
                        );
                    }else{
                        var allDatas = finalOptions.datas;
                                
                        $scope.selects[finalOptions.optionModel].allDatas = allDatas;
                        
                        if (utils.isEmpty(finalOptions.initFilter)){
                            $scope.selects[finalOptions.optionModel].datas = allDatas;
                        }else{
                            var datas = [];
                            for (var i = 0; i < allDatas.length; i++){
                                if (allDatas[i][finalOptions.initFilter.attr] == finalOptions.initFilter.value){
                                    datas.push(utils.clone(allDatas[i]));
                                }
                            }
                            
                            $scope.selects[finalOptions.optionModel].datas = datas;
                        }
                    }
                    
                    //初始值
                    if (!utils.isEmpty(finalOptions.initValue)){
                        $scope.selects[finalOptions.optionModel].selected = finalOptions.initValue;
                    }
                    
                    
                    //值变更事件
                    if (finalOptions.selectChangeEvent instanceof Function){
                        var variable = utils.isEmpty(finalOptions.ngModel) ? 'selects.' + finalOptions.optionModel + '.selected' : finalOptions.ngModel;
                        $scope.$watch(variable,
                            function (newVal, oldVal) {                       
                                finalOptions.selectChangeEvent.call(this,newVal,oldVal);
                            }
                        );
                    }
                }
                
                return {
                    scope: $scope,
                    options: finalOptions,
                    /**
                     * 根据值获取对应的对象
                     */
                    getData:function(value){
                        var scope = this.scope,
                            options = this.options,
                            datas = scope.selects[options.optionModel].datas;
                        if (utils.isEmpty(datas)){
                            return {value: options.initValue, name: options.initName};
                        }else if (utils.isEmpty(value)){
                            return value;
                        }else{
                            for (var i = 0; i < datas.length; i++){
                                if (datas[i].value == value){
                                    return datas[i];
                                }
                            }
                        }
                    },
                    /**
                     * 获取所有的值
                     */
                    getAllData:function(value){
                        var scope = this.scope,
                            options = this.options,
                            datas = scope.selects[options.optionModel].datas;
                        return datas;
                    },
                    /**
                     * 获取选中值
                     */
                    getSelected: function(){
                        return utils.isEmpty(this.scope.selects[this.options.optionModel].selected) ? '' : this.scope.selects[this.options.optionModel].selected;
                    },
                    /**
                     * 获取选择的名称
                     */
                    getSelectedName: function(){
                        return this.getData(this.getSelected()).name;
                    },
                    /**
                     * 选中指定值
                     * 如果refresh=true 则传入的值为[{name=name,value=value}]
                     */
                    select: function(newVal){
                        var scope = this.scope,
                            options = this.options
                        if (options.refresh){
                            scope.selects[options.optionModel].datas = newVal;
                            if (utils.isEmpty(options.ngModel)){
                                scope.selects[options.optionModel].selected = newVal[0].value;
                            }else{
                                eval("this.scope." + options.ngModel + "=" + newVal[0].value);
                            }
                        }else{
                            if (utils.isEmpty(options.ngModel)){
                                scope.selects[options.optionModel].selected = newVal;
                            }else{
                                eval("this.scope." + options.ngModel + "=" + newVal);
                            }
                        }
                    },
                    /**
                     * 选中第一个值
                     */
                    selectFirst: function(newVal){
                        var scope = this.scope,
                            options = this.options,
                            datas = scope.selects[options.optionModel].datas;
                        if (!utils.isEmpty(datas) && datas.length > 0){
                            this.select(datas[0].value)
                        }
                    },
                    /**
                     * 刷新数据
                     */
                    refresh: function(params){
                        var scope = this.scope,
                            options = this.options
                            options.params = params;

                        httpUtils.queryList(params,
                            function(result){
                                var allDatas = result.datas.gridDatas;
                                
                                for (var i = 0; i < allDatas.length; i++){
                                    allDatas[i].value = allDatas[i].value + "";
                                }
                                
                                scope.selects[options.optionModel].allDatas = allDatas;
                                
                                if (utils.isEmpty(options.initFilter)){
                                    scope.selects[options.optionModel].datas = allDatas;
                                }else{
                                    var datas = [];
                                    for (var i = 0; i < allDatas.length; i++){
                                        if (allDatas[i][options.initFilter.attr] == options.initFilter.value){
                                            datas.push(utils.clone(allDatas[i]));
                                        }
                                    }
                                    
                                    scope.selects[options.optionModel].datas = datas;
                                }
                            }
                        );
                    },
                    /**
                     * 清空选择
                     */
                    clear: function(){
                        if (this.options.multiple){
                            this.select([]);
                        }else{
                            this.select('');
                        }
                    },
                    /**
                     * 过滤结果集
                     */
                    filter: function(attr,value,logic){
                        var scope = this.scope,
                            options = this.options,
                            datas = [],
                            allDatas = scope.selects[options.optionModel].allDatas;
                        
                        if (utils.isEmpty(allDatas)) return;
                        
                        if (logic == "!="){
                            if (value instanceof Object){
                                for (var i = 0; i < allDatas.length; i++){
                                    var needFilter = false
                                    for (var j = 0; j < value.length; j++){
                                        if (allDatas[i][attr] == value[j]){
                                            needFilter = true;
                                            break;
                                        }
                                    }
                                    if (!needFilter){
                                        datas.push(utils.clone(allDatas[i]));
                                    }
                                }
                            }else{                      
                                for (var i = 0; i < allDatas.length; i++){
                                    if (allDatas[i][attr] != value){
                                        datas.push(utils.clone(allDatas[i]));
                                    }
                                }
                            }
                        }else{
                            if (value instanceof Object){
                                for (var i = 0; i < allDatas.length; i++){
                                    for (var j = 0; j < value.length; j++){
                                        if (allDatas[i][attr] == value[j]){
                                            datas.push(utils.clone(allDatas[i]));
                                        }
                                    }   
                                }
                            }else{                      
                                for (var i = 0; i < allDatas.length; i++){
                                    if (allDatas[i][attr] == value){
                                        datas.push(utils.clone(allDatas[i]));
                                    }
                                }
                            }
                        }
                        
                        scope.selects[options.optionModel].datas = datas;
                    },
                    /**
                     * 取消过滤
                     */
                    clearFilter: function(){
                        var scope = this.scope,
                            options = this.options,
                            datas = [],
                            allDatas = scope.selects[options.optionModel].allDatas;
                            
                        if (utils.isEmpty(allDatas)) return;
                        
                        for (var i = 0; i < allDatas.length; i++){
                            datas.push(utils.clone(allDatas[i]));
                        }
                        
                        scope.selects[options.optionModel].datas = datas;
                    }
                };
            }
        }
    }
]);

/**=========================================================
 * Service: simple-ui-grid.js
 =========================================================*/
App.service('SimpleUiGrid', ['$timeout', '$translate', 'HttpUtils','Utils','toaster', 
    function($timeout, $translate, httpUtils, utils, toaster) {
        'use strict';
        
        return {
            init: function($scope, options) {
                var defaultOptions = {
                    /**
                     * 表格配置绑定的变量名
                     */
                    optionModel: 'gridOptions',
                    /**
                     * 分页配置绑定的变量名
                     */
                    pageOptionModel: 'pageOptionModel',
                    /**
                     * 后台排序配置绑定的变量名
                     */
                    sortOptionModel: 'sortOptionModel',
                    /**
                     * 表格Api绑定的变量名
                     */
                    gridApi: 'gridApi',
                    /**
                     * 自定义查询
                     * 如果是通用查询 无需配置
                     */
                    url: '',
                    /**
                     * 是否分页
                     */
                    needPage: true,
                    /**
                     * 初始分页大小
                     */
                    pageSize: null,
                    /**
                     * 分页类型 
                     * common：正常分页
                     * date：日期分页
                     */
                    pageType: 'date',
                    /**
                     * 是否需要导出
                     */
                    needExport: true, 
                    /**
                     * 是否多选
                     */
                    multiSelect: false,
                    /**
                     * 是否显示列尾
                     */
                    showColumnFooter: false,
                    /**
                     * 当列信息从后台取时 指定列尾的聚合类型
                     */
                    footerAggregationType: null,
                    /**
                     * 自动选中第一行
                     */
                    autoSelect: false,
                    /**
                     * 是否后台排序
                     */
                    remoteSort: false,
                    /**
                     * 是否表格树
                     */
                    expandable: false,
                    /**
                     * 当列信息从后台取时 可以在前端进行增加头列
                     */
                    headColumns: [],
                    /**
                     * 表格列
                     */
                    columns: [
                        //解决树模式下动态列头导致的列头高度无法自适应的问题
                        {
                            displayName: '',
                            field: 'keep_column_head_height_in_tree_view'
                        }
                    ],
                    /**
                     * 当列信息从后台取时 可以在前端进行增加尾列
                     */
                    footColumns: [],
                    /**
                     * 是否显示指标列
                     */
                    showMetricColumn: true,
                    /**
                     * 增加行合计列
                     */
                    needRowTotal: false,
                    /**
                     * 增加行趋势
                     */
                    needRowSparkLine: false,
                    /**
                     * 菜单配置
                     */
                    menus: [],
                    /**
                     * 行高
                     */
                    rowHeight: 30,
                    /**
                     * 自定义行模版
                     */
                    rowTemplate: null,
                    /**
                     * 控制器中的查询方法 用于切换页时查询
                     */
                    controllerSearchFn: options.controllerSearchFn,
                    /**
                     * 注册事件方法
                     */
                    registerApiFn: options.registerApiFn,
                    /**
                     * 数据加载完成后触发
                     */
                    afterDataLoadEvent: options.afterDataLoadEvent,
                    /**
                     * 双击事件触发调用的方法名
                     */
                    rowDoubleClickEventName: options.rowDoubleClickEventName
                };
                
                var finalOptions = angular.extend(defaultOptions,options);

                $scope[finalOptions.optionModel] = {
                    enableRowSelection: true,
                    enableRowHeaderSelection: false,
                    multiSelect: finalOptions.multiSelect,
                    modifierKeysToMultiSelect: true,
                    showTreeExpandNoChildren: true,
                    enableExpandAll: false,
                    noUnselect: true,
                    enableHorizontalScrollbar: true,
                    rowHeight: finalOptions.rowHeight,
                    enableColumnMenus: false,
                    columnDefs: finalOptions.columns,
                    showColumnFooter: finalOptions.showColumnFooter,
                    flatEntityAccess: true,
                    onRegisterApi: function(gridApi) {
                        $scope[finalOptions.gridApi] = gridApi;
                        //排序
                        if(finalOptions.remoteSort){
                            gridApi.core.on.sortChanged($scope, function(grid, sortColumns) {
                                $scope[finalOptions.pageOptionModel].sort = sortColumns;
                                finalOptions.controllerSearchFn.call();
                            });
                        }
                        //分页
                        if(finalOptions.needPage){
                            gridApi.pagination.on.paginationChanged($scope, function (newPage, pageSize) {
                                $scope[finalOptions.pageOptionModel].page = newPage;
                                $scope[finalOptions.pageOptionModel].pageSize = pageSize;
                                finalOptions.controllerSearchFn.call();
                            });
                        }
                        //自定义
                        if (!utils.isEmpty(finalOptions.registerApiFn)){
                            finalOptions.registerApiFn.call(this,gridApi);
                        }
                    }
                };
                
                //自定义模版
                if(!utils.isEmpty(finalOptions.rowTemplate)) {
                    $scope[finalOptions.optionModel].rowTemplate = finalOptions.rowTemplate;
                }else if (finalOptions.rowDoubleClickEventName){
                    //需要双击行事件
                    var fnName = 'grid.appScope.' + finalOptions.rowDoubleClickEventName + '(row,col)'
                    $scope[finalOptions.optionModel].rowTemplate =
                        "<div ng-dblclick='" + fnName + "' ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.uid\" \
                              ui-grid-one-bind-id-grid=\"rowRenderIndex + '-' + col.uid + '-cell'\" \
                              class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" \
                              role=\"{{col.isRowHeader ? 'rowheader' : 'gridcell'}}\" ui-grid-cell> \
                        </div>"
                }
                
                //排序
                if(finalOptions.remoteSort) {
                    $scope[finalOptions.optionModel].useExternalSorting = true;
                }
                
                //分页
                if(finalOptions.needPage){
                    var pageSize = finalOptions.pageSize;
                    if (utils.isEmpty(pageSize)){
                        pageSize = finalOptions.pageType == 'date' ? 7 : 10;
                    }
                    $scope[finalOptions.pageOptionModel] = {
                        page: 1,
                        pageSize: pageSize,
                        sort: []
                    };
                    
                    $scope[finalOptions.optionModel].paginationPageSizes = [10, 25, 50, 100];
                    $scope[finalOptions.optionModel].paginationPageSize = pageSize;
                    $scope[finalOptions.optionModel].useExternalPagination = true;
                    
                    //分页类型
                    if (finalOptions.pageType == 'date'){
                        $scope[finalOptions.optionModel].paginationTemplate = 'ui-grid/datePagination';
                        $scope[finalOptions.optionModel].paginationPageSizes = [7];
                    }
                }     
                
                //导出
                if (finalOptions.needExport){
                    $scope[finalOptions.optionModel].enableGridMenu = true;
                    $scope[finalOptions.optionModel].gridMenuShowHideColumns = false;
                    $scope[finalOptions.optionModel].gridMenuCustomItems = [
                        {
                            title: $translate.instant('button.EXPORT'),
                            action: function ($event) {
                                //text|dataIndex|width
                                var options = this.grid.options,
                                    fileName = utils.dateFormat(new Date(),'yyyyMMddhhmmss') + '.xlsx',
                                    url = utils.getBackendPath('/common/exportToExcel') + '?filename=' + fileName
                                
                                url += '&vType=export';

                                if (!utils.isEmpty(options.queryParams)){
                                    for (var paramName in options.queryParams){
                                        if (options.queryParams[paramName] != undefined && paramName != 'vType'){
                                            url += '&' + paramName + '=' + options.queryParams[paramName];
                                        }
                                    }
                                }
                                var columnInfos = '';
                                if (finalOptions.pageType == 'date'){
                                    for (var i = 0; i < finalOptions.headColumns.length; i++){
                                        if (finalOptions.headColumns[i].field != 'widgets' && !((finalOptions.headColumns[i].visible + '') == 'false')){
                                            columnInfos += finalOptions.headColumns[i].displayName + '|' + finalOptions.headColumns[i].field + '|100,';
                                        }
                                    }
                                    columnInfos += $translate.instant('metric') + '|metric_name|100,';
                                }else{
                                    for (var i = 0; i < options.columnDefs.length; i++){
                                        if (options.columnDefs[i].field != 'widgets' && !((options.columnDefs[i].visible + '') == 'false')){
                                            columnInfos += options.columnDefs[i].displayName + '|' + options.columnDefs[i].field + '|100,';
                                        }
                                    }
                                }

                                var form = document.createElement('form');
                                form.setAttribute('style','display:none');  
                                form.setAttribute('target','');  
                                form.setAttribute('method','post');
                                form.setAttribute('action',url);
                                
                                var input = document.createElement("input");  
                                input.type = "text";  
                                input.name = "column";  
                                input.value = escape(columnInfos);
                                
                                form.appendChild(input);
                                
                                document.body.appendChild(form);
                                
                                form.submit();
                                form.remove();
                            }
                        }
                    ]
                }
                
                //表格菜单
                if (finalOptions.menus.length > 0){
                    $scope[finalOptions.optionModel].enableGridMenu = true;
                    $scope[finalOptions.optionModel].gridMenuShowHideColumns = false;
                    if (utils.isEmpty($scope[finalOptions.optionModel].gridMenuCustomItems)){
                        $scope[finalOptions.optionModel].gridMenuCustomItems = finalOptions.menus;
                    }else{
                        $scope[finalOptions.optionModel].gridMenuCustomItems = utils.mergeArray($scope[finalOptions.optionModel].gridMenuCustomItems, finalOptions.menus);
                    }
                }
                            
                return {
                    scope: $scope,
                    options: finalOptions,
                    /**
                     * 更新表格数据
                     */
                    draw: function(params){                        
                        var scope = this.scope;
                        var options = this.options;
                        
                        scope[options.optionModel].status = 'loading';

                        if (utils.isEmpty(params)){
                            params = scope[options.optionModel].queryParams;
                        }else{
                            scope[options.optionModel].queryParams = params;
                        }
                        params.vType = 'grid';
                        
                        scope[options.optionModel].data = [];
                        if (options.columns.length == 0){
                            scope[options.optionModel].columnDefs = [];
                        }
                        
                        var url = options.url;
                        
                        if (utils.isEmpty(url)){
                            url = options.needPage ? utils.getQueryPageUrl() : utils.getQueryListUrl();
                        }
                        
                        if(options.needPage){               
                            params.page = scope[options.pageOptionModel].page;
                            params.pageSize = scope[options.pageOptionModel].pageSize;
                        }
                        
                        if(options.remoteSort){
                            if (scope[options.pageOptionModel].sort.length > 0){
                                params.sort = scope[options.pageOptionModel].sort[0].field;
                                params.sortDirection = scope[options.pageOptionModel].sort[0].sort.direction;
                            }else{
                                params.sort = null;
                                params.sortDirection = null;
                            }
                        }
                        
                        httpUtils.get(url,params,
                            function (result) {
                                if (!utils.isEmpty(result.datas.gridColumns)){
                                    //后台定义列信息
                                    var columns = result.datas.gridColumns;
                                    
                                    if (!options.showMetricColumn){
                                        //隐藏指标列
                                        columns = columns.slice(1,columns.length);
                                    }
                                    if (options.headColumns.length > 0){
                                        columns = utils.mergeArray(options.headColumns,columns);
                                    }
                                    if (options.footColumns.length > 0){
                                        columns = utils.mergeArray(columns,options.footColumns);
                                    }
                                    
                                    if (options.needRowTotal){
                                        columns.push({
                                            displayName: $translate.instant('total'),
                                            field: 'total',
                                            cellFilter: "numberFormat",
                                            headerCellClass: "align-right",
                                            cellClass: "align-right",
                                            cellTemplate: '\
                                                <div class="ui-grid-cell-contents" >\
                                                    <span style="font-weight: bold">{{COL_FIELD CUSTOM_FILTERS}}</span>\
                                                </div>\
                                            '
                                        })
                                    }

                                    if (options.needRowSparkLine){
                                        columns.push({
                                            displayName: '',
                                            field: 'sparkline',
                                            cellTemplate: '\
                                                <div style="text-align:center;margin-top: 5px">\
                                                    <sparkline data-type="bar" data-bar-color="#5d9cec" data-height="20" data-bar-width="3" \
                                                        data-bar-spacing="2" values="{{COL_FIELD}}" data-resize="true"></sparkline>\
                                                </div>\
                                            '
                                        })
                                    }

                                    for (var i = 0; i < columns.length; i++){
                                        columns[i].cellTooltip = function(row, col) {
                                            return row.entity.metric_tips;
                                        }
                                        
                                        if (columns[i].field == "metric_name"){
                                            columns[i].displayName = $translate.instant('metric');
                                        }

                                        if (!utils.isEmpty(options.footerAggregationType) && utils.isTimeStr(columns[i].field)){
                                            columns[i].aggregationType = options.footerAggregationType;
                                            columns[i].footerCellClass = columns[i].cellClass;
                                            columns[i].footerCellFilter = columns[i].cellFilter;
                                        }
                                    }
                                    
                                    scope[options.optionModel].columnDefs = columns;
                                }
                                
                                if (options.needRowTotal || options.needRowSparkLine){
                                    var dates = [];
                                    for (var k = 0; k < columns.length; k++){
                                        if (utils.isDateString(columns[k].field)){
                                            dates.push(columns[k].field);
                                        }
                                    }

                                    for (var i = 0; i < result.datas.gridDatas.length; i++){
                                        var total = 0,datas = [];
                                        for (var j = 0; j < dates.length; j++){
                                            total += parseInt(result.datas.gridDatas[i][dates[j]]);
                                            datas.push(result.datas.gridDatas[i][dates[j]]);
                                        }
                                        result.datas.gridDatas[i].sparkline = datas.join(',');
                                        result.datas.gridDatas[i].total = total
                                    }
                                }

                                if (options.expandable){
                                    for (var i = 0; i < result.datas.gridDatas.length; i++){
                                        result.datas.gridDatas[i].$$treeLevel = 0;
                                        result.datas.gridDatas[i].$$childrenLoaded = false;                                        
                                    }
                                }
                                
                                scope[options.optionModel].data = result.datas.gridDatas;
                                scope[options.optionModel].totalItems = result.totalCount;
                                
                                if (options.autoSelect){
                                    $timeout(function(){
                                        scope[options.gridApi].selection.selectRowByVisibleIndex(0);
                                    },0)
                                }
                                
                                if (options.afterDataLoadEvent instanceof Function){
                                    options.afterDataLoadEvent.call(this,scope[options.optionModel].data,scope[options.optionModel].columnDefs);
                                }

                                scope[options.optionModel].status = 'succeed';
                            },
                            function(data,header,config,status){
                                scope[options.optionModel].status = 'fail';
                                // toaster.pop('error', '', '数据获取失败 请重试');
                            }
                        );
                    },
                    /**
                     * 获取所有数据
                     */
                    getAll: function(){
                        var scope = this.scope;
                        var options = this.options;
                        
                        return scope[options.optionModel].data;
                    },
                    /**
                     * 获取行数
                     */
                    getCount: function(){
                        var scope = this.scope;
                        var options = this.options;
                        
                        return scope[options.optionModel].data.length;
                    },
                    /**
                     * 获取选中行
                     */
                    getSelection: function(){
                        var scope = this.scope;
                        var options = this.options;
                        
                        return scope[options.gridApi].selection.getSelectedRows();
                    },
                    /**
                     * 获取行的位置
                     */
                    getIndex: function(data){
                        var scope = this.scope;
                        var options = this.options;
                        
                        var allDatas = scope[options.optionModel].data;
                        for (var i = 0; i < allDatas.length; i++){
                            if (data.$$hashKey === allDatas[i].$$hashKey){
                                return i;
                            }
                        }
                    },
                    /**
                     * 获取行
                     */
                    getRowByIndex: function(index){
                        var scope = this.scope;
                        var options = this.options;
                        
                        return scope[options.optionModel].data[index];
                    },
                    /**
                     * 清空表格数据
                     */
                    clear: function(){
                        var scope = this.scope;
                        var options = this.options;
                        
                        scope[options.optionModel].data = [];
                        scope[options.optionModel].totalItems = 0;
                    },
                    /**
                     * 增加一行
                     */
                    addRow: function(data,index){
                        var scope = this.scope;
                        var options = this.options;
                        
                        if (utils.isEmpty(index)){
                            scope[options.optionModel].data.push(data);
                        }else{
                            scope[options.optionModel].data.splice(index, 0, data);
                        }
                    },
                    /**
                     * 删除一行
                     */
                    deleteRow: function(data){
                        var scope = this.scope;
                        var options = this.options;
                        
                        var datas = scope[options.optionModel].data;
                        utils.removeFromArray(datas,data,'$$hashKey');
                    },
                     /**
                     * 通过位置删除行
                     */
                    deleteRowByIndex: function(index,length){
                        var scope = this.scope;
                        var options = this.options;
                        
                        var datas = scope[options.optionModel].data;
                        datas.splice(index, utils.coalesce(length,1));
                    },
                    /**
                     * 选中指定行
                     */
                    selectRow: function(index){
                        var scope = this.scope;
                        var options = this.options;
                        
                        scope[options.gridApi].selection.selectRowByVisibleIndex(index);
                    },
                    /**
                     * 选中最后一行
                     */
                    selectLastRow: function(){
                        var scope = this.scope;
                        scope[options.gridApi].selection.selectRowByVisibleIndex([scope[options.gridApi].grid.rows.length - 1]);
                    },
                    /**
                     * 跳转到指定页数
                     */
                    goToPage: function(page){
                        var scope = this.scope;
                        var options = this.options;
                        
                        if ($scope[options.pageOptionModel].page == page){
                            options.controllerSearchFn.call();
                        }else{
                            scope[options.gridApi].pagination.seek(page);
                        }   
                    },
                    /**
                     * 展开行
                     */
                    expandRow: function(row){
                        var scope = this.scope;
                        var options = this.options;
                        
                        return scope[options.gridApi].treeBase.expandRow(row);
                    },
                    getGridOptions: function(){
                        var scope = this.scope;
                        var options = this.options;

                        return scope[options.optionModel];
                    }
                }   
            }
        }
    }
]);

/**=========================================================
 * Service: tour.js
 =========================================================*/
App.service('Tour', 
    function() {
        'use strict';
        
        return {
            init: function($scope){
                //修复兼容性问题
                // BootstrapTour is not compatible with z-index based layout
                // so adding position:static for this case makes the browser
                // to ignore the property
                var section = angular.element('.wrapper > section');
                section.css({'position': 'static'});
                // finally restore on destroy and reuse the value declared in stylesheet
                $scope.$on('$destroy', function(){
                    section.css({'position': ''});
                });
            }  
        }
    }
);
    
/**=========================================================
 * Filter: number-format.js
 * add thousands separator
 =========================================================*/
 
 App.filter('numberFormat', ['Utils', 
    function(utils){
        return function(value){
            if (value != undefined && value != null){
                value = value + "";
                if (value.indexOf('（') > 0 || value.indexOf('(') > 0){
                    var index = value.indexOf('（') > 0 ? value.indexOf('（') : value.indexOf('(');
                    var formatPart = value.substring(0,index);
                    if (!isNaN(formatPart)){
                        return utils.numberFormat(formatPart) + value.substring(index);
                    }
                }else{
                    if (!isNaN(value)){
                        return utils.numberFormat(value);
                    }
                }   
            }else {
                return '-';
            }
            
            return value;
        };
    }
 ])
/**=========================================================
 * Filter: number-format.js
 * add thousands separator
 =========================================================*/
 
 App.filter('roundHalfDown', ['Utils', 
    function(utils){
        return function(value,scale){
            if (value != undefined && value != null){
                return value.toFixed(scale);
            }else {
                return '-';
            }
        };
    }
 ])
/**=========================================================
 * Module: custom.js
 * real app config
 =========================================================*/

var tzadmin = angular.module('tzadmin', ['angle']);

tzadmin.run(["$log", function($log) {

//   $log.log('I\'m a line from custom.js');

}]);

tzadmin.config(["RouteHelpersProvider", function(RouteHelpersProvider) {

  // Custom Route definition
  
}]);

tzadmin.config(['$stateProvider', '$locationProvider', '$urlRouterProvider', 'RouteHelpersProvider',
    function ($stateProvider, $locationProvider, $urlRouterProvider, helper) {
        'use strict';

        $stateProvider
        .state('app.account-trustUserCenter', {
            url: '/account/trustUserCenter',
            templateUrl: helper.basepath('account/trustUserCenter.html')
        })
    }
]);

/**=========================================================
 * Controller: TrustUserCenterController
  =========================================================*/
tzadmin.controller('TrustUserCenterController', ['$scope', 'Utils', 'HttpUtils', 'Datepicker', 'SimpleUiGrid', 'ngDialog', 'toaster',
    function($scope, utils, httpUtils, datepickerService, simpleUiGridService, ngDialog, toaster) {
        var createDate = datepickerService.init($scope,{initValue: ''});

        var trustUserGridColumns = [
            {
                displayName: '注册时间',
                field: 'create_date',
                width: '150'
            },
            {
                displayName: '注册账号',
                field: 'mobile',
                width: '100'
            },
            {
                displayName: '绑定邮箱',
                field: 'mail',
                width: '150'
            },
            {
                displayName: '企业名称',
                field: 'company_name'
            },
            {
                displayName: '所属商务',
                field: 'enname',
                width: '80'
            },
            {
                displayName: '账户余额',
                field: 'fund',
                width: '80',
                cellClass: "align-right"
            },
            {
                displayName: 'API欠费',
                field: 'arrears',
                width: '80'
            },
            {
                displayName: '状态',
                field: 'frozen_status',
                width: '80'
            },
            { 
                name: '操作', 
                field: 'widgets', 
                width: '150',
                enableCellEdit: false,
                cellTemplate: '\
                    <div class="ui-grid-cell-contents" style="text-align:center;">\
                        <button ng-click="grid.appScope.editTrustUser(row.entity)" title="编辑" class="btn btn-xs btn-success">\
                            <em class="fa fa-edit"></em>\
                        </button>\
                        <button ng-click="grid.appScope.editFee(row.entity)" title="报价" class="btn btn-xs btn-warning">\
                            <em class="fa fa-rmb"></em>\
                        </button>\
                        <button ng-click="grid.appScope.frozen(row.entity)" title="冻结" class="btn btn-xs btn-info">\
                            <em class="fa fa-lock"></em>\
                        </button>\
                    </div>\
                '
            }
        ];
        
        $scope.queryParams = {namespace: 'AccountMapper.queryTrustUser'};
        $scope.searchTrustUserGrid = function() {
            $scope.queryParams.createDate = utils.dateFormat(createDate.getDate(),'yyyy-MM-dd');
            trustUserGrid.draw($scope.queryParams);
        }; 

        var trustUserGrid = simpleUiGridService.init($scope, 
            {
                optionModel: 'trustUserGridOptions',
                pageOptionModel: 'trustUserGridPageOptions',
                gridApi: 'trustUserGridApi',
                columns: trustUserGridColumns,
                pageType: 'common',
                needExport: false,
                remoteSort: true,
                controllerSearchFn: $scope.searchTrustUserGrid
            }
        );

        $scope.editFee = function(data){
            ngDialog.openConfirm({
                template: 'editFeeDialog',
                className: 'ngdialog-theme-default',
                appendClassName: 'ngdialog-lg',
                scope: $scope,
                controller: ['$scope', function($scope) {
                    $scope.getTrustUserFee(data.tid);
                }]
            }).then(function (value) {
                httpUtils.post('/trustUserApiFee/save', $scope.userFee,
                    function(result){
                        if (result.success){
                            toaster.pop('success', '', '保存成功');
                        }else{
                            toaster.pop('error', '', result.msg);
                        }
                    },
                    function(result){
                        toaster.pop('error', '', '保存失败');
                    }
                );
            });
        }

        $scope.getTrustUserFee = function(id){
            httpUtils.queryList(
                {
                    namespace:'AccountMapper.getTrustUserFee',
                    id: id
                },
                function(result){
                    if (result.success){
                        $scope.userFee = result.datas.gridDatas[0];
                    }else{
                        $scope.userFee = null;
                    }
                },
                function(result){
                    toaster.pop('error', '', '获取用户计费失败');
                }
            );
        }

        $scope.searchTrustUserGrid();
    }
]);

/**=========================================================
 * Directive: datepicker-combine.js
 =========================================================*/

 tzadmin.directive('combineDatepicker', ['Utils',
    function(utils) {
        'use strict';
        
        return {
            restrict: 'EA',
            replace: true,
            template: function($element,$attrs){
                var optionModel = utils.isEmpty($attrs.optionModel) ? 'dateRange' : $attrs.optionModel,
                    ngModel = 'combineDatePickers.' + optionModel,
                    searchFn = utils.isEmpty($attrs.search) ? "search()" : $attrs.search;
                return '\
                    <table>\
                        <tr>\
                            <td style="padding:8px"><datepicker ng-model="' + ngModel + '.startDate"></datepicker></td>\
                            <td style="padding:8px"><span class="control-label">~</span></td>\
                            <td style="padding:8px"><datepicker ng-model="' + ngModel + '.endDate"></datepicker></td>\
                            <td style="padding:8px">\
                                <ui-select ng-model="' + ngModel + '.quickSelects.currentSelect" style="width: 130px;">\
                                    <ui-select-match>\
                                        {{$translate.instant($select.selected.name)}}\
                                    </ui-select-match>\
                                    <ui-select-choices class="animated bounceIn" repeat="option in ' + ngModel + '.quickSelects.options">\
                                        <span>{{$translate.instant(option.name)}}</span>\
                                    </ui-select-choices>\
                                </ui-select>\
                            </td>\
                            <td style="padding:8px">\
                                <a class="btn btn-primary btn-search" ng-click="' + searchFn + '">\
                                    <i class="fa fa-search"></i>\
                                    {{$translate.instant("button.SEARCH")}}\
                                </a>\
                            </td>\
                        </tr>\
                    </table>\
                '
            },
            link: function($scope, $element, $attrs){
                var optionModel = utils.isEmpty($attrs.optionModel) ? 'dateRange' : $attrs.optionModel,
                    ngModel = 'combineDatePickers.' + optionModel,
                    searchFn = utils.isEmpty($attrs.search) ? "search" : $attrs.search.substring(0,$attrs.search.indexOf('('));
         
                $scope.$watch(ngModel + ".quickSelects.currentSelect.value", 
                    function (newVal, oldVal) { 
                        if (newVal != oldVal){
                            var startDate,
                                today = new Date(),
                                endDate = utils.addDate(today, "day", -1);
                            if (newVal == 'past7days'){
                                startDate = utils.addDate(today, "day", -7);
                            }else if (newVal == 'past15days'){
                                startDate = utils.addDate(today, "day", -15);
                            }else if (newVal == 'past30days'){
                                startDate = utils.addDate(today, "day", -30);
                            }else if (newVal == 'past1year'){
                                startDate = utils.addDate(endDate, "year", -1);
                            }
                            
                            $scope.combineDatePickers[optionModel].startDate.date = startDate;
                            $scope.combineDatePickers[optionModel].endDate.date = endDate;
                            
                            // if ($scope[searchFn] instanceof Function){
                            //     $scope[searchFn].call(this);
                            // }
                        }
                    }
                );
                
                $scope.$watch(ngModel + ".startDate.date", 
                    function (newVal, oldVal) {                       
                        $scope.combineDatePickers[optionModel].endDate.dateOptions.minDate = newVal;
                    }
                );
                
                $scope.$watch(ngModel + ".endDate.date", 
                    function (newVal, oldVal) {                       
                        $scope.combineDatePickers[optionModel].startDate.dateOptions.maxDate = newVal;
                    }
                );
            }
        }
    }
]);

/**=========================================================
 * Directive: monthpicker-combine.js
 =========================================================*/

 tzadmin.directive('combineMonthpicker', ['Utils',
    function(utils) {
        'use strict';
        
        return {
            restrict: 'EA',
            replace: true,
            template: function($element,$attrs){
                var optionModel = utils.isEmpty($attrs.optionModel) ? 'monthRange' : $attrs.optionModel,
                    ngModel = 'combineMonthPickers.' + optionModel,
                    searchFn = utils.isEmpty($attrs.search) ? "search()" : $attrs.search;
                return '\
                    <table>\
                        <tr>\
                            <td style="padding:8px"><datepicker ng-model="' + ngModel + '.startMonth" format="yyyy-MM"></datepicker></td>\
                            <td style="padding:8px"><span class="control-label">~</span></td>\
                            <td style="padding:8px"><datepicker ng-model="' + ngModel + '.endMonth" format="yyyy-MM"></datepicker></td>\
                            <td style="padding:8px">\
                                <a class="btn btn-primary btn-search" ng-click="' + searchFn + '">\
                                    <i class="fa fa-search"></i>\
                                    {{$translate.instant("button.SEARCH")}}\
                                </a>\
                            </td>\
                        </tr>\
                    </table>\
                '
            },
            link: function($scope, $element, $attrs){
                var optionModel = utils.isEmpty($attrs.optionModel) ? 'monthRange' : $attrs.optionModel,
                    ngModel = 'combineMonthPickers.' + optionModel,
                    searchFn = utils.isEmpty($attrs.search) ? "search" : $attrs.search.substring(0,$attrs.search.indexOf('('));
  
                $scope.$watch(ngModel + ".startMonth.date", 
                    function (newVal, oldVal) {                       
                        $scope.combineMonthPickers[optionModel].endMonth.dateOptions.minDate = newVal;
                    }
                );
                
                $scope.$watch(ngModel + ".endMonth.date", 
                    function (newVal, oldVal) {                       
                        $scope.combineMonthPickers[optionModel].startMonth.dateOptions.maxDate = newVal;
                    }
                );
            }
        }
    }
]);

/**=========================================================
 * Service: echarts-util.js
 =========================================================*/

 tzadmin.service('EchartsUtils', ['HttpUtils','Utils', 
    function(httpUtils, utils) {
        'use strict';
        
        return {
            /**
             * 指标折线图
             */
            initMetricLineChartObject: function($scope,options) {
                var defaultOptions = {
                    optionModel: 'echartsOption',
                    name: 'chart',
                    showLabel: false,     
                    showLegend: true,
                    showToolbox: false,
                    type: '',
                    params: {},
                    /**
                     * 画图前可以自主修改option
                     */
                    beforeDrawFn: null,
                    /**
                     * 用户判定系列属于哪个y坐标轴
                     */
                    yAxisData: null
                };
                
                var finalOptions = angular.extend(defaultOptions,options);
                
                return {
                    scope: $scope,
                    options: finalOptions,
                    currentParam: finalOptions.params,
                    draw: function(params){
                        var scope = this.scope,
                            options = this.options,
                            yAxisData = options.yAxisData,
                            chart = scope[options.name];
                        this.currentParam = params;
                              
                        if (!utils.isEmpty(chart)){
                            chart.showLoading();
                        }
                            
                        httpUtils.get(utils.getQueryListUrl(),params,
                            function (result) {
                                var columns = result.datas.gridColumns;
                                var datas = result.datas.gridDatas,
                                    chartOption = {};
                                if (datas.length > 0){
                                    var legendData = [],
                                        xAxisData = [],
                                        series = [],
                                        doubleYAxis = !(utils.isEmpty(yAxisData) || utils.isEmpty(yAxisData[0]) || utils.isEmpty(yAxisData[1]));
                                    
                                    //xAxisData
                                    for (var k = 0; k < columns.length; k++){
                                        if (utils.isDateString(columns[k].field)){
                                            xAxisData.push(columns[k].field);
                                        }
                                    }
                                    
                                    //series
                                    var leftDatas = [],rightDatas = [];
                                    for (var i = 0; i < datas.length; i++){
                                        var serieData = [];
                                        for (var j = 0; j < xAxisData.length; j++){							
                                            serieData.push((utils.isEmpty(datas[i][xAxisData[j]]) || datas[i][xAxisData[j]] == '-') ? 0 : (datas[i][xAxisData[j]] + "").replace("%","") / 1);
                                        }
                                        if (doubleYAxis){
                                            if (utils.isArrayContains(yAxisData[0],datas[i].metric_id)){
                                                series.push({
                                                    name: datas[i].metric_name,
                                                    type: 'line',
                                                    data: serieData,
                                                    symbolSize: 8,
                                                    label: {
                                                        normal: {
                                                            show: options.showLabel,
                                                            position: 'top'
                                                        }
                                                    }
                                                });
                                                leftDatas.push(datas[i]);
                                            }else{
                                                series.push({
                                                    name: datas[i].metric_name,
                                                    type: 'line',
                                                    yAxisIndex: 1,
                                                    data: serieData,
                                                    symbolSize: 10,
                                                    label: {
                                                        normal: {
                                                            show: options.showLabel,
                                                            position: 'top'
                                                        }
                                                    }
                                                });
                                                rightDatas.push(datas[i]);
                                            }
                                        }else {
                                            series.push({
                                                name: datas[i].metric_name,
                                                type: 'line',
                                                data: serieData,
                                                symbolSize: 8,
                                                label: {
                                                    normal: {
                                                        show: options.showLabel,
                                                        position: 'top'
                                                    }
                                                }
                                            });
                                        }
                                        
                                        legendData.push(datas[i].metric_name);
                                    }
       
                                    
                                    if (options.type == 'area' || options.type == 'areaStack'){
                                        if (options.type == 'area') {
                                            for (var i = 0; i < series.length; i++){
                                                series[i].itemStyle = {normal: {areaStyle: {type: 'default'}}};
                                            }
                                        }else {
                                            for (var i = 0; i < series.length; i++){
                                                series[i].itemStyle = {normal: {areaStyle: {type: 'default'}}};
                                                series[i].stack = 'stack1';
                                            }
                                        }
                                    }
                                    
                                    //yAxis、grid
                                    var yAxis,grid;
                                    if (doubleYAxis){
                                        yAxis = [
                                            {
                                                type : 'value',
                                                scale: true,
                                                axisLabel: {
                                                    formatter: function (value, index) {
                                                        if (leftDatas[0].show_type == "3"){
                                                            return utils.numberFormat(value) + " %";
                                                        }else if (value > 1000000){
                                                            return utils.numberFormat(value / 1000000) + " M"
                                                        }else {
                                                            return utils.numberFormat(value)
                                                        }
                                                        
                                                    }
                                                }
                                            },
                                            {
                                                type : 'value',
                                                scale: true,
                                                axisLabel: {
                                                    formatter: function (value, index) {
                                                        if (rightDatas[0].show_type == "3"){
                                                            return utils.numberFormat(value) + " %";
                                                        }else if (value > 1000000){
                                                            return utils.numberFormat(value / 1000000) + " M"
                                                        }else {
                                                            return utils.numberFormat(value)
                                                        }
                                                        
                                                    }
                                                }
                                            }
                                        ];
                                        
                                        grid = {
                                            y: 10,
                                            y2: 40,
                                            x: 60,
                                            x2: 80
                                        }
                                    }else{
                                        yAxis = [
                                            {
                                                type : 'value',
                                                scale: true,
                                                axisLabel: {
                                                    formatter: function (value, index) {
                                                        if (datas[0].show_type == "3"){
                                                            return utils.numberFormat(value) + " %";
                                                        }else if (value > 1000000){
                                                            return utils.numberFormat(value / 1000000) + " M"
                                                        }else {
                                                            return utils.numberFormat(value)
                                                        }
                                                        
                                                    }
                                                }
                                            }
                                        ];
                                        
                                        grid = {
                                            y: 10,
                                            y2: 40,
                                            x: 60,
                                            x2: 40
                                        }
                                    }
                                    
                                    if (options.showLegend){
                                        grid.y += 50;
                                    }
                                    
                                    //toolbox
                                    var toolbox = {
                                        show: options.showToolbox,
                                        y: 18,
                                        feature: {
                                            // dataZoom: {show: true},
                                            magicType: {show: true, type: ['line', 'bar', 'stack', 'tiled']},
                                            restore: {show: true},
                                            saveAsImage: {show: true}
                                        }
                                    }
                                    
                                    chartOption = {
                                        tooltip: {
                                            trigger: 'axis',
                                            showDelay: 0,
                                            formatter: function (params,ticket,callback) {
                                                var res = '<span>' + params[0].name + '</span><br/>';
                                                for (var i = 0; i < params.length; i++) {
                                                    
                                                    if (datas[i].show_type == "3"){
                                                        res += '<span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:' + params[i].color + '"></span>' +
                                                                params[i].seriesName + '：' + params[i].value + "%" +
                                                            '<br/>';
                                                    }else{
                                                        res += '<span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:' + params[i].color + '"></span>' +
                                                                params[i].seriesName + '：' + utils.numberFormat(params[i].value + "") +
                                                            '<br/>';
                                                    }
                                                    
                                                }
            
                                                return res;
                                            }
                                        },
                                        toolbox: toolbox,
                                        grid: grid,
                                        legend: {
                                            show: options.showLegend,
                                            data: legendData,
                                            x: 'left'
                                        },
                                        yAxis: yAxis,
                                        xAxis: {
                                            type: 'category',
                                            data: xAxisData,
                                            boundaryGap: false,
                                            splitLine: false
                                        },
                                        series: series
                                    };
                                }
                                
                                if (options.beforeDrawFn instanceof Function){
                                    options.beforeDrawFn.call(this,chartOption);
                                }
                                
                                scope[options.optionModel] = chartOption;
                            }
                        );
                    }
                }
            },
            /**
             * 维度折线图
             */
            initDimensionLineChartObject: function($scope,options){
                var defaultOptions = {
                    optionModel: 'echartsOption',
                    name: 'chart',
                    dimension: '',
                    showLabel: false,
                    showLegend: true,
                    showToolbox: false,
                    params: {}
                };
                
                var finalOptions = angular.extend(defaultOptions,options);
                
                return {
                    scope: $scope,
                    options: finalOptions,
                    currentParam: finalOptions.params,
                    draw: function(params){
                        var scope = this.scope,
                            options = this.options,
                            chart = scope[options.name];
                        this.currentParam = params;
                        
                        if (!utils.isEmpty(chart)){
                            chart.showLoading();
                        }
                        
                        httpUtils.get(utils.getQueryListUrl(),params,
                            function (result) {
                                var columns = result.datas.gridColumns;
                                var datas = result.datas.gridDatas,
                                    chartOption = {};
                                if (datas.length > 0){
                                    var legendData = [];
                                    var xAxisData = [];
                                    var series = [];
                            
                                    for (var k = 0; k < columns.length; k++){
                                        if (utils.isDateString(columns[k].field)){
                                            xAxisData.push(columns[k].field);
                                        }
                                    }
                                    
                                    for (var i = 0; i < datas.length; i++){
                                        legendData.push(datas[i][options.dimension]);
                                        
                                        var serieData = [];
                                        for (var j = 0; j < xAxisData.length; j++){							
                                            serieData.push((utils.isEmpty(datas[i][xAxisData[j]]) || datas[i][xAxisData[j]] == '-') ? 0 : (datas[i][xAxisData[j]] + "").replace("%","") / 1);
                                        }
                                        
                                        series.push({
                                            name: datas[i][options.dimension],
                                            type: 'line',
                                            yAxisIndex: 0,
                                            data: serieData,
                                            symbolSize: 8,
                                            label: {
                                                normal: {
                                                    show: options.showLabel,
                                                    position: 'top'
                                                }
                                            }
                                        });
                                    }
                                    
                                    //yAxis
                                    var yAxis = [
                                        {
                                            type : 'value',
                                            scale: true
                                        }
                                    ];
                                    
                                    if (datas[0].show_type == "3"){
                                        yAxis[0].axisLabel = {
                                            formatter: '{value} %'
                                        };
                                    }
                                    
                                    //toolbox
                                    var toolbox = {
                                        show: options.showToolbox,
                                        y: 18,
                                        feature: {
                                            // dataZoom: {show: true},
                                            magicType: {show: true, type: ['line', 'bar', 'stack', 'tiled']},
                                            restore: {show: true},
                                            saveAsImage: {show: true}
                                        }
                                    }
                                    
                                    //grid
                                    var grid = {
                                        y: 40,
                                        y2: 40,
                                        x: 60,
                                        x2: 40
                                    }
                                    
                                    if (options.showToolbox){
                                        grid.y += 20;
                                    }
                                    
                                    var metricName = datas[0].metric_name;
                                    
                                    chartOption = {
                                        tooltip: {
                                            trigger: 'axis',
                                            showDelay: 0,
                                            formatter: function (params,ticket,callback) {
                                                var res = '<span>' + params[0].name + '</span><br/>';
                                                res += '<span>' + metricName + '</span><br/>';
                                                for (var i = 0; i < params.length; i++) {
                                                    var value = params[i].value + "";
                                                    value = utils.numberFormat(value);
                                                    
                                                    res += '<span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:' + params[i].color + '"></span>' +
                                                                params[i].seriesName + ' : ' + value + ((datas[i].show_type == "3") ? "%" : "") +
                                                            '<br/>';
                                                }
            
                                                return res;
                                            }
                                        },
                                        calculable: true,
                                        toolbox: toolbox,
                                        grid: grid,
                                        yAxis: yAxis,
                                        xAxis: [
                                            {
                                                type: 'category',
                                                data: xAxisData,
                                                boundaryGap: false,
                                                splitLine: false
                                            }
                                        ],
                                        series: series,
                                        legend: {
                                            show: options.showLegend,
                                            data: legendData,
                                            x: 'left'
                                        }
                                    };
                                }
                            
                                scope[options.optionModel] = chartOption;
                            }
                        );
                    }
                }
            },
            /**
             * 条形图
             * 返回数据格式
             * {
             *      name: y轴值
             *      value: x轴值
             *      title: 系列名
             * }
             */
            initPieChartObject: function($scope,options){
                var defaultOptions = {
                    optionModel: 'echartsOption',
                    params: {},
                    /**
                     * 画图前可以自主修改option
                     */
                    beforeDrawFn: null,
                };

                var finalOptions = angular.extend(defaultOptions,options);

                return {
                    scope: $scope,
                    options: finalOptions,
                    currentParam: finalOptions.params,
                    draw: function(params){
                        var scope = this.scope,
                            options = this.options;
                        this.currentParam = params;

                        httpUtils.get(utils.getQueryListUrl(),params,
                            function (result) {
                                var datas = result.datas.gridDatas,
                                    chartOption = {};;
                                if (datas.length > 0){
                                    var item = {
                                        title: datas[0].title,
                                        legendDatas: [],
                                        serieDatas: []
                                    };

                                    for (var i = 0; i < datas.length; i++) {
                                        item.legendDatas.push(datas[i].name);                
                                        item.serieDatas.push({value:datas[i].value, name:datas[i].name}); 
                                    }

                                    chartOption = {
                                        tooltip: {
                                            trigger: 'item',
                                            formatter: function(params, ticket, callback){
                                                return params.seriesName + '<br>' + params.name + '：' + utils.numberFormat(params.value) + '(' + params.percent + '%)'
                                            }
                                        },
                                        grid: {
                                            bottom: 200
                                        },
                                        series: [{
                                            name: item.title,
                                            type: 'pie',
                                            selectedMode : 'single',
                                            radius: 120,
                                            center: ['50%','50%'],
                                            data: item.serieDatas,
                                            label: {
                                                normal: {
                                                    textStyle: {
                                                        fontSize: 16
                                                    }
                                                }
                                            }
                                        }]
                                    }
                                }

                                scope[options.optionModel] = chartOption;
                            }
                        )
                    }
                }
            },
            /**
             * 条形图
             * 返回数据格式
             * {
             *      name: y轴值
             *      value: x轴值
             *      serie: 系列名
             * }
             */
            initTopBarChartObject: function($scope,options){
                var defaultOptions = {
                    optionModel: 'echartsOption',
                    params: {},
                    /**
                     * 画图前可以自主修改option
                     */
                    beforeDrawFn: null,
                };
                
                var finalOptions = angular.extend(defaultOptions,options);
                
                return {
                    scope: $scope,
                    options: finalOptions,
                    currentParam: finalOptions.params,
                    draw: function(params){
                        var scope = this.scope,
                            options = this.options;
                        this.currentParam = params;
                            
                        httpUtils.get(utils.getQueryListUrl(),params,
                            function (result) {
                                var datas = result.datas.gridDatas,
                                    chartOption = {};;
                                if (datas.length > 0){
                                    
                                    var yAxisData = [];
                                    var seriesData = [];
                                    
                                    for (var i = 0; i < datas.length; i++){
                                        yAxisData.push(datas[i].name);
                                        seriesData.push(datas[i].value);
                                    }
                                    
                                    chartOption = {
                                        tooltip: {
                                            trigger: 'axis',
                                            axisPointer: {
                                                type : 'shadow'
                                            },
                                            showDelay: 0,
                                            formatter: function (params,ticket,callback) {
                                                var res = '<span>' + params[0].name.split("\\n").join(" ") + '</span><br/>';
                                                res += '<span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:' + params[0].color + '"></span>' +
                                                            params[0].seriesName + '：' + utils.numberFormat(params[0].value + "") +
                                                        '<br/>';
            
                                                return res;
                                            }
                                        },
                                        calculable: true,
                                        xAxis: [
                                            {
                                                type: 'value',
                                                boundaryGap: [0, 0.01],
                                                axisLine: {
                                                    show: false 
                                                }
                                            }
                                        ],
                                        yAxis : [
                                            {
                                                type: 'category',
                                                data: yAxisData,
                                                axisLabel: {
                                                    formatter: function(val){
                                                        return val.split("\\n").join("\n");
                                                    }
                                                },
                                                splitLine: {
                                                    show: false
                                                }
                                            }
                                        ],
                                        series : [
                                            {
                                                name: datas[0].serie,
                                                type: 'bar',
                                                data: seriesData
                                            }
                                        ],
                                        grid: {
                                            y: 20,
                                            y2: 40,
                                            x: 130
                                        }
                                    };
                                    
                                    if (options.beforeDrawFn instanceof Function){
                                        options.beforeDrawFn.call(this,chartOption,datas);
                                    }
                                }

                                scope[options.optionModel] = chartOption;
                            }
                        );
                    }
                }
            },
            /**
             * 地图
             * 返回数据格式
             * {
             *      name: 地区名
             *      value: 值
             *      serie: 系列名
             * }
             * 数据需要倒序排序
             */
            initMapChartObject: function($scope,options){
                var defaultOptions = {
                    optionModel: 'echartsOption',
                    showLabel: true
                };
                
                var finalOptions = angular.extend(defaultOptions,options);
                
                return {
                    scope: $scope,
                    options: finalOptions,
                    currentParam: {},
                    draw: function(params){
                        var scope = this.scope,
                            options = this.options;
                        this.currentParam = params;
                            
                        httpUtils.get(utils.getQueryListUrl(),params,
                            function (result) {
                                var datas = result.datas.gridDatas,
                                    chartOption = {};
                                if (datas.length > 0){
                                    var seriesData = [];
                                    
                                    for (var i = 0; i < datas.length; i++){
                                        seriesData.push({
                                            name: datas[i].name,
                                            value: datas[i].value,
                                            showName: utils.isEmpty(datas[i].show_name) ? datas[i].name : datas[i].show_name
                                        });
                                    }
                                    
                                    chartOption = {
                                        tooltip : {
                                            trigger: 'item',
                                            formatter: function(params, ticket, callback) {
                                                return params.data.showName + '<br>' + params.seriesName + '：' + params.value;
                                            }
                                        },
                                        visualMap: {
                                            min: 0,
                                            max: datas[0].value,
                                            x: 'left',
                                            y: 'bottom',
                                            text:['高','低'],
                                            calculable : true
                                        },
                                        series : [
                                            {
                                                name: datas[0].serie,
                                                type: 'map',
                                                mapType: 'china',
                                                itemStyle: {
                                                    normal: {
                                                        label:{
                                                            show:finalOptions.showLabel
                                                        }
                                                    },
                                                    emphasis: {
                                                        label:{
                                                            show:finalOptions.showLabel
                                                        }
                                                    }
                                                },
                                                data: seriesData
                                            }
                                        ]
                                    };
                                }
                            
                                scope[options.optionModel] = chartOption;
                            }
                        );
                    }
                }
            },
            /**
             * 自定义图
             */
            initChartObject: function($scope,options){
                var defaultOptions = {
                    optionModel: 'echartsOption'
                };
                
                var finalOptions = angular.extend(defaultOptions,options);
                
                return {
                    scope: $scope,
                    options: finalOptions,
                    draw: function(option){
                        this.scope[this.options.optionModel] = option;
                    }
                }
            }
        }
    }
]);

/**=========================================================
 * Service: monthpicker-combine.js
 =========================================================*/

 tzadmin.service('CombineMonthpicker', ['Utils',
    function(utils) {
        'use strict';
        
        return {
            init: function($scope,options) {
                var date = new Date();
                date.setDate(1);
                
                var defaultOptions = {
                    optionModel: 'monthRange',
                    startMonth: utils.addDate(date, "month", -6),
                    endMonth: date
                }

                var finalOptions = angular.extend(defaultOptions,options);
                
                if (utils.isEmpty($scope.combineMonthPickers)){
                    $scope.combineMonthPickers = {}
                }
                
                $scope.combineMonthPickers[finalOptions.optionModel] = {};
                //开始日期
                $scope.combineMonthPickers[finalOptions.optionModel].startMonth = {
                    date: finalOptions.startMonth,
                    dateOptions: {
                        datepickerMode: 'month',
                        minMode: 'month',
                        startingDay: 1,
                        maxDate: finalOptions.endMonth
                    },
                    opened: false
                };
                //结束日期
                $scope.combineMonthPickers[finalOptions.optionModel].endMonth = {
                    date: finalOptions.endMonth,
                    dateOptions: {
                        datepickerMode: 'month',
                        minMode: 'month',
                        startingDay: 1,
                        minDate: finalOptions.startMonth
                    },
                    opened: false
                }
                
                return {
                    scope: $scope,
                    options: finalOptions,
                    addParam: function(params,format){
                        if (utils.isEmpty(format)){
                            format = 'yyyyMM';
                        }
                        params.startMonth = utils.dateFormat(new Date($scope.combineMonthPickers[this.options.optionModel].startMonth.date),format);
                        params.endMonth = utils.dateFormat(new Date($scope.combineMonthPickers[this.options.optionModel].endMonth.date),format);
                    },
                    getStartMonth: function(){
                        return new Date($scope.combineMonthPickers[this.options.optionModel].startMonth.date);
                    },
                    getEndMonth: function(){
                        return new Date($scope.combineMonthPickers[this.options.optionModel].endMonth.date);
                    }
                }
            }
        }
    }
]);
